{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":29762,"databundleVersionId":2541532,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":336693,"sourceType":"datasetVersion","datasetId":143878},{"sourceId":1782442,"sourceType":"datasetVersion","datasetId":1059701},{"sourceId":3932654,"sourceType":"datasetVersion","datasetId":2334639},{"sourceId":3947411,"sourceType":"datasetVersion","datasetId":24658},{"sourceId":6244141,"sourceType":"datasetVersion","datasetId":3587899},{"sourceId":11766825,"sourceType":"datasetVersion","datasetId":7374262},{"sourceId":11786457,"sourceType":"datasetVersion","datasetId":7385034},{"sourceId":11826282,"sourceType":"datasetVersion","datasetId":7393981},{"sourceId":11826352,"sourceType":"datasetVersion","datasetId":7393923},{"sourceId":11873425,"sourceType":"datasetVersion","datasetId":7393689}],"dockerImageVersionId":29987,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"### Setup Dependencies","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nfrom tqdm import tqdm\nimport cv2\nimport torch\nfrom torch.autograd import Variable as V\nimport torchvision.models as models\nfrom torchvision import transforms as trn\nfrom torch.nn import functional as F\nimport os\nimport numpy as np\nimport cv2\nfrom PIL import Image\nimport gc\ngc.enable()\nimport matplotlib.pyplot as plt","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-22T14:51:04.451556Z","iopub.execute_input":"2025-05-22T14:51:04.451865Z","iopub.status.idle":"2025-05-22T14:51:06.058610Z","shell.execute_reply.started":"2025-05-22T14:51:04.451839Z","shell.execute_reply":"2025-05-22T14:51:06.057952Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Load classes and I/O labels of Places365 Dataset","metadata":{}},{"cell_type":"code","source":"list_in_sun = \"amusement_arcade\",\"art_school\",\"bakery_shop\",\"basement\",\"beauty_salon\",\"building_facade\",\"fastfood_restaurant\",\"parking_lot\",\"playground\",\"sky\",\"auto_factory\",\"garbage_dump\",\"street\",\"videostore\",\"diner_outdoor\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-21T03:30:59.382771Z","iopub.execute_input":"2025-05-21T03:30:59.383080Z","iopub.status.idle":"2025-05-21T03:30:59.388399Z","shell.execute_reply.started":"2025-05-21T03:30:59.383050Z","shell.execute_reply":"2025-05-21T03:30:59.386891Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import shutil\nimport os\nfrom pathlib import Path\n\n# Define source directories\nsrc_dir_caltech = '/kaggle/input/caltech-101/caltech-101'\nsrc_dir_celebrity = '/kaggle/input/50k-celebrity-faces-image-dataset/Celebrity_Faces_Dataset'\ndst_dir = '/kaggle/working/non_landmark'\n\n# Create the destination directory if it doesn't exist\nos.makedirs(dst_dir, exist_ok=True)\n\n# Copy Caltech-101 categories to the destination directory\nfor category in os.listdir(src_dir_caltech):\n    category_path = os.path.join(src_dir_caltech, category)\n    if os.path.isdir(category_path):\n        shutil.copytree(category_path, os.path.join(dst_dir, category))\n\n# Copy the celebrity face images (first 40,000 images) to a new subfolder in non_landmark\ncelebrity_dst_dir = os.path.join(dst_dir, 'celebrity_faces')\nos.makedirs(celebrity_dst_dir, exist_ok=True)\n\n# Assuming the celebrity faces are sequentially numbered from 000003.jpg onwards\nfor i in range(1, 40000):  # Starting from 000003.jpg to 000040000.jpg\n    img_name = f\"{i:06}.jpg\"  # Format the image number as 6 digits\n    src_img_path = os.path.join(src_dir_celebrity, img_name)\n    \n    # Check if the source image exists before copying\n    if os.path.exists(src_img_path):\n        dst_img_path = os.path.join(celebrity_dst_dir, img_name)\n        shutil.copy(src_img_path, dst_img_path)\n\nprint(\"All Caltech-101 and celebrity face images have been copied to the target directory.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T14:51:10.917846Z","iopub.execute_input":"2025-05-22T14:51:10.918165Z","iopub.status.idle":"2025-05-22T14:51:10.982623Z","shell.execute_reply.started":"2025-05-22T14:51:10.918131Z","shell.execute_reply":"2025-05-22T14:51:10.981491Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\ndf = pd.read_csv(\"/kaggle/input/id-2-names-landmark/ID_to_names/train_with_landmark_names.csv\",encoding = \"Latin1\")  # replace with your actual filename\ntotal_ids = df[\"id\"].count()\nprint(\"Total ID entries:\", total_ids)\nunique_ids = df[\"landmark_id\"].nunique()\nprint(\"Unique landmark id entries:\", unique_ids)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-21T04:00:07.178392Z","iopub.execute_input":"2025-05-21T04:00:07.178734Z","iopub.status.idle":"2025-05-21T04:00:07.247012Z","shell.execute_reply.started":"2025-05-21T04:00:07.178704Z","shell.execute_reply":"2025-05-21T04:00:07.246343Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import shutil\nimport os\nfrom pathlib import Path\n\n# Define source directories\nsrc_dir_caltech = '/kaggle/input/caltech-101/caltech-101'\nsrc_dir_celebrity = '/kaggle/input/50k-celebrity-faces-image-dataset/Celebrity_Faces_Dataset'\nsrc_dir_sun397 = '/kaggle/input/sun397-50-50/train/train'\ndst_dir = '/kaggle/working/non_landmark'\n\n# Create the destination directory if it doesn't exist\nos.makedirs(dst_dir, exist_ok=True)\n\n# 1. Copy Caltech-101 categories to the destination directory\nfor category in os.listdir(src_dir_caltech):\n    category_path = os.path.join(src_dir_caltech, category)\n    if os.path.isdir(category_path):\n        dst_category_path = os.path.join(dst_dir, category)\n        os.makedirs(dst_category_path, exist_ok=True)\n        for img_file in os.listdir(category_path):\n            src_img_path = os.path.join(category_path, img_file)\n            dst_img_path = os.path.join(dst_category_path, img_file)\n            if os.path.isfile(src_img_path):\n                shutil.copy(src_img_path, dst_img_path)\n\n# 2. Copy 10,000 celebrity face images to a subfolder\ncelebrity_dst_dir = os.path.join(dst_dir, 'celebrity_faces')\nos.makedirs(celebrity_dst_dir, exist_ok=True)\n\nfor i in range(1, 10001):  # 10,000 images\n    img_name = f\"{i:06}.jpg\"\n    src_img_path = os.path.join(src_dir_celebrity, img_name)\n    if os.path.exists(src_img_path):\n        dst_img_path = os.path.join(celebrity_dst_dir, img_name)\n        shutil.copy(src_img_path, dst_img_path)\n\n# 3. Copy selected SUN397 categories\nsun_categories = [\n    \"amusement_arcade\", \"art_school\", \"bakery_shop\", \"basement\", \"beauty_salon\",\n    \"building_facade\", \"fastfood_restaurant\", \"parking_lot\", \"playground\",\n    \"auto_factory\", \"garbage_dump\", \"street\", \"videostore\", \"diner_outdoor\"\n]\n\nsun_dst_dir = os.path.join(dst_dir, 'sun397')\nos.makedirs(sun_dst_dir, exist_ok=True)\n\nfor category in sun_categories:\n    category_path = os.path.join(src_dir_sun397, category)\n    if os.path.isdir(category_path):\n        for img_file in os.listdir(category_path):\n            src_img_path = os.path.join(category_path, img_file)\n            dst_img_path = os.path.join(sun_dst_dir, f\"{category}_{img_file}\")\n            shutil.copy(src_img_path, dst_img_path)\n\nprint(\"✅ Caltech-101, Celebrity Faces (10k), and selected SUN397 images copied to non_landmark directory.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T14:32:14.239502Z","iopub.execute_input":"2025-05-22T14:32:14.239813Z","iopub.status.idle":"2025-05-22T14:34:37.511710Z","shell.execute_reply.started":"2025-05-22T14:32:14.239785Z","shell.execute_reply":"2025-05-22T14:34:37.510748Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nfrom pathlib import Path\nimport shutil\n\n# Load the CSV\ndf = pd.read_csv('/kaggle/input/id-2-names-landmark/ID_to_names/train_with_landmark_names.csv', encoding='ISO-8859-1')\ndf.columns = ['id', 'landmark_id', 'landmark_name']  # Ensure correct columns\n\n# Define new sample size\nimages_per_landmark = 200\n\n# Target directory\ntarget_dir = Path('/kaggle/working/landmark')\n\n# ❌ Delete existing folder if it exists\nif target_dir.exists() and target_dir.is_dir():\n    shutil.rmtree(target_dir)\n\n# ✅ Recreate target directory\ntarget_dir.mkdir(parents=True, exist_ok=True)\n\n# Sample up to 70 images per landmark\nsampled_df = df.groupby('landmark_id').apply(\n    lambda x: x.sample(n=min(len(x), images_per_landmark), random_state=42)\n).reset_index(drop=True)\n\nprint(f\"✅ Selected {len(sampled_df)} images across {sampled_df['landmark_id'].nunique()} landmarks.\")\n\n# Copy selected images\ncopied = 0\nfor _, row in sampled_df.iterrows():\n    image_id = row['id']\n    subfolder = f\"{image_id[0]}/{image_id[1]}/{image_id[2]}\"\n    src_path = Path(f\"/kaggle/input/landmark-recognition-2021/train/{subfolder}/{image_id}.jpg\")\n    dst_path = target_dir / f\"{image_id}.jpg\"\n\n    if src_path.exists():\n        shutil.copy(src_path, dst_path)\n        copied += 1\n\nprint(f\"✅ Copied {copied} images to {target_dir}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T14:34:37.513527Z","iopub.execute_input":"2025-05-22T14:34:37.513766Z","iopub.status.idle":"2025-05-22T14:37:26.628220Z","shell.execute_reply.started":"2025-05-22T14:34:37.513736Z","shell.execute_reply":"2025-05-22T14:37:26.627507Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from pathlib import Path\n\n# Count landmark images\nlandmark_path = Path('/kaggle/working/landmark')\nlandmark_count = len(list(landmark_path.glob('*.jpg')))\n\n# Count non-landmark images (recursively search all subfolders)\nnon_landmark_path = Path('/kaggle/working/non_landmark')\nnon_landmark_count = len(list(non_landmark_path.glob('**/*.jpg')))\n\nprint(f\"Landmark images: {landmark_count}\")\nprint(f\"Non-landmark images: {non_landmark_count}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T14:37:26.629678Z","iopub.execute_input":"2025-05-22T14:37:26.629916Z","iopub.status.idle":"2025-05-22T14:37:26.875893Z","shell.execute_reply.started":"2025-05-22T14:37:26.629892Z","shell.execute_reply":"2025-05-22T14:37:26.875168Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from pathlib import Path\nimport pandas as pd\nfrom sklearn.model_selection import train_test_split\n\n# List images and assign labels\n#landmark_images = [(str(p), 1) for p in Path('/kaggle/working/landmark').glob('*.jpg')]\n#non_landmark_images = [(str(p), 0) for p in Path('/kaggle/working/non_landmark').rglob('*.jpg')]\n\n# Combine\ndf = pd.DataFrame(landmark_images + non_landmark_images, columns=['filepath', 'label'])\n\n# Train/val/test split\ntrain_df, temp_df = train_test_split(df, test_size=0.3, stratify=df['label'], random_state=42)\nval_df, test_df = train_test_split(temp_df, test_size=0.5, stratify=temp_df['label'], random_state=42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T16:50:16.220464Z","iopub.execute_input":"2025-05-22T16:50:16.220878Z","iopub.status.idle":"2025-05-22T16:50:16.280661Z","shell.execute_reply.started":"2025-05-22T16:50:16.220843Z","shell.execute_reply":"2025-05-22T16:50:16.278885Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"all_images = landmark_images + non_landmark_images\n\n# Create DataFrame\ndf = pd.DataFrame(all_images, columns=['filepath', 'label'])\n\n# Check df is loaded correctly\nprint(df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T16:51:07.060816Z","iopub.execute_input":"2025-05-22T16:51:07.061142Z","iopub.status.idle":"2025-05-22T16:51:29.817649Z","shell.execute_reply.started":"2025-05-22T16:51:07.061117Z","shell.execute_reply":"2025-05-22T16:51:29.816730Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(df['label'].head())\nprint(type(df.loc[0, 'label']))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T16:51:52.884059Z","iopub.execute_input":"2025-05-22T16:51:52.884492Z","iopub.status.idle":"2025-05-22T16:52:15.419105Z","shell.execute_reply.started":"2025-05-22T16:51:52.884437Z","shell.execute_reply":"2025-05-22T16:52:15.418365Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom torch.utils.data import Dataset, DataLoader\nfrom PIL import Image\nfrom torchvision import transforms\n\nclass LandmarkDataset(Dataset):\n    def __init__(self, dataframe, transform=None):\n        self.data = dataframe.reset_index(drop=True)\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        img_path = self.data.loc[idx, 'filepath']\n        label = self.data.loc[idx, 'label']\n        image = Image.open(img_path).convert('RGB')  # Ensure all images are in RGB format\n        if self.transform:\n            image = self.transform(image)\n        return image, label\n\n# Transforms\ntrain_transform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomRotation(20),  # Augmentation for rotation\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.2),  # Random color jitter\n    transforms.ToTensor(),\n    transforms.Normalize([0.5]*3, [0.5]*3)  # Normalizing RGB channels\n])\n\ntest_transform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize([0.5]*3, [0.5]*3)  # Normalizing RGB channels\n])\n\n# Datasets and Loaders\ntrain_ds = LandmarkDataset(train_df, transform=train_transform)\nval_ds = LandmarkDataset(val_df, transform=test_transform)\ntest_ds = LandmarkDataset(test_df, transform=test_transform)\n\ntrain_loader = DataLoader(train_ds, batch_size=32, shuffle=True)\nval_loader = DataLoader(val_ds, batch_size=32)\ntest_loader = DataLoader(test_ds, batch_size=32)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T14:39:19.113474Z","iopub.execute_input":"2025-05-22T14:39:19.113792Z","iopub.status.idle":"2025-05-22T14:39:19.127233Z","shell.execute_reply.started":"2025-05-22T14:39:19.113767Z","shell.execute_reply":"2025-05-22T14:39:19.126302Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision import models\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\n\n# Define device\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# Load pretrained MobileNetV2\nmodel = models.mobilenet_v2(pretrained=True)\n\n# Replace classifier for binary classification (NO Sigmoid here)\nmodel.classifier = nn.Sequential(\n    nn.Dropout(0.3),\n    nn.Linear(model.last_channel, 1)  # Output raw logits\n)\n\n# Move model to device\nmodel.to(device)\n\n# Use BCEWithLogitsLoss (includes sigmoid internally)\ncriterion = nn.BCEWithLogitsLoss()\n\n# Optimizer\noptimizer = optim.Adam(model.parameters(), lr=1e-4)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T15:32:16.620734Z","iopub.execute_input":"2025-05-15T15:32:16.620972Z","iopub.status.idle":"2025-05-15T15:32:21.791371Z","shell.execute_reply.started":"2025-05-15T15:32:16.620947Z","shell.execute_reply":"2025-05-15T15:32:21.790674Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport matplotlib.pyplot as plt\nfrom IPython.display import clear_output\nfrom sklearn.metrics import precision_score, recall_score, f1_score, roc_auc_score\n\ndef train_model(model, train_loader, val_loader, criterion, optimizer, epochs=3, device='cuda'):\n    history = {\n        'train_loss': [], 'train_acc': [], 'val_acc': [],\n        'train_precision': [], 'train_recall': [], 'train_f1': [], 'train_auc': [],\n        'val_precision': [], 'val_recall': [], 'val_f1': [], 'val_auc': []\n    }\n\n    for epoch in range(epochs):\n        model.train()\n        running_loss = 0.0\n        correct = 0\n        all_train_labels = []\n        all_train_preds = []\n\n        # Training loop\n        for images, labels in train_loader:\n            images = images.to(device)\n            labels = labels.float().unsqueeze(1).to(device)\n\n            optimizer.zero_grad()\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n            loss.backward()\n            optimizer.step()\n\n            running_loss += loss.item()\n            correct += ((outputs > 0.5).float() == labels).sum().item()\n\n            all_train_labels.extend(labels.cpu().numpy())\n            all_train_preds.extend(outputs.cpu().detach().numpy())\n\n        # Calculate training metrics\n        train_acc = correct / len(train_loader.dataset)\n        train_precision = precision_score(all_train_labels, (torch.tensor(all_train_preds) > 0.5).int(), average='binary')\n        train_recall = recall_score(all_train_labels, (torch.tensor(all_train_preds) > 0.5).int(), average='binary')\n        train_f1 = f1_score(all_train_labels, (torch.tensor(all_train_preds) > 0.5).int(), average='binary')\n        train_auc = roc_auc_score(all_train_labels, all_train_preds)\n\n        history['train_loss'].append(running_loss)\n        history['train_acc'].append(train_acc)\n        history['train_precision'].append(train_precision)\n        history['train_recall'].append(train_recall)\n        history['train_f1'].append(train_f1)\n        history['train_auc'].append(train_auc)\n\n        # Validation loop\n        model.eval()\n        val_correct = 0\n        all_val_labels = []\n        all_val_preds = []\n        with torch.no_grad():\n            for images, labels in val_loader:\n                images = images.to(device)\n                labels = labels.float().unsqueeze(1).to(device)\n                outputs = model(images)\n                val_correct += ((outputs > 0.5).float() == labels).sum().item()\n\n                all_val_labels.extend(labels.cpu().numpy())\n                all_val_preds.extend(outputs.cpu().detach().numpy())\n\n        # Calculate validation metrics\n        val_acc = val_correct / len(val_loader.dataset)\n        val_precision = precision_score(all_val_labels, (torch.tensor(all_val_preds) > 0.5).int(), average='binary')\n        val_recall = recall_score(all_val_labels, (torch.tensor(all_val_preds) > 0.5).int(), average='binary')\n        val_f1 = f1_score(all_val_labels, (torch.tensor(all_val_preds) > 0.5).int(), average='binary')\n        val_auc = roc_auc_score(all_val_labels, all_val_preds)\n\n        history['val_acc'].append(val_acc)\n        history['val_precision'].append(val_precision)\n        history['val_recall'].append(val_recall)\n        history['val_f1'].append(val_f1)\n        history['val_auc'].append(val_auc)\n\n        # Print and plot progress\n        clear_output(wait=True)  # Clear previous output in notebook\n        print(f\"Epoch {epoch+1}/{epochs}\")\n        print(f\"Train Loss: {running_loss:.4f}, Train Acc: {train_acc:.4f}, Train Precision: {train_precision:.4f}, \"\n              f\"Train Recall: {train_recall:.4f}, Train F1: {train_f1:.4f}, Train AUC: {train_auc:.4f}\")\n        print(f\"Val Acc: {val_acc:.4f}, Val Precision: {val_precision:.4f}, Val Recall: {val_recall:.4f}, \"\n              f\"Val F1: {val_f1:.4f}, Val AUC: {val_auc:.4f}\")\n\n        # Plot after each epoch\n        plt.figure(figsize=(12, 8))\n\n        # Loss and Accuracy\n        plt.subplot(2, 2, 1)\n        plt.plot(history['train_loss'], label='Train Loss')\n        plt.xlabel('Epoch')\n        plt.ylabel('Loss')\n        plt.title('Training Loss')\n        plt.legend()\n\n        plt.subplot(2, 2, 2)\n        plt.plot(history['train_acc'], label='Train Acc')\n        plt.plot(history['val_acc'], label='Val Acc')\n        plt.xlabel('Epoch')\n        plt.ylabel('Accuracy')\n        plt.title('Training and Validation Accuracy')\n        plt.legend()\n\n        # Precision, Recall, F1, AUC\n        plt.subplot(2, 2, 3)\n        plt.plot(history['train_precision'], label='Train Precision')\n        plt.plot(history['val_precision'], label='Val Precision')\n        plt.xlabel('Epoch')\n        plt.ylabel('Precision')\n        plt.title('Precision')\n        plt.legend()\n\n        plt.subplot(2, 2, 4)\n        plt.plot(history['train_f1'], label='Train F1 Score')\n        plt.plot(history['val_f1'], label='Val F1 Score')\n        plt.xlabel('Epoch')\n        plt.ylabel('F1 Score')\n        plt.title('F1 Score')\n        plt.legend()\n\n        plt.tight_layout()\n        plt.show()\n\n    return history","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T15:32:21.792761Z","iopub.execute_input":"2025-05-15T15:32:21.793100Z","iopub.status.idle":"2025-05-15T15:32:21.817358Z","shell.execute_reply.started":"2025-05-15T15:32:21.793065Z","shell.execute_reply":"2025-05-15T15:32:21.816465Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = train_model(model, train_loader, val_loader, criterion, optimizer)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T15:32:21.819132Z","iopub.execute_input":"2025-05-15T15:32:21.819476Z","iopub.status.idle":"2025-05-15T16:24:47.590787Z","shell.execute_reply.started":"2025-05-15T15:32:21.819439Z","shell.execute_reply":"2025-05-15T16:24:47.589863Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix, classification_report\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\ndef evaluate_model(model, test_loader):\n    model.eval()\n    all_preds = []\n    all_labels = []\n\n    with torch.no_grad():\n        for images, labels in test_loader:\n            images = images.to(device)\n            outputs = torch.sigmoid(model(images))\n            preds = (outputs > 0.5).int().cpu().numpy()\n            all_preds.extend(preds)\n            all_labels.extend(labels.int().cpu().numpy())\n\n    cm = confusion_matrix(all_labels, all_preds)\n    print(\"Classification Report:\")\n    print(classification_report(all_labels, all_preds, target_names=['Non-Landmark', 'Landmark']))\n\n    plt.figure(figsize=(5, 4))\n    sns.heatmap(cm, annot=True, fmt=\"d\", cmap=\"Blues\", xticklabels=['Non-Landmark', 'Landmark'], yticklabels=['Non-Landmark', 'Landmark'])\n    plt.xlabel(\"Predicted\")\n    plt.ylabel(\"True\")\n    plt.title(\"Confusion Matrix\")\n    plt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T16:24:47.592982Z","iopub.execute_input":"2025-05-15T16:24:47.593357Z","iopub.status.idle":"2025-05-15T16:24:47.784016Z","shell.execute_reply.started":"2025-05-15T16:24:47.593309Z","shell.execute_reply":"2025-05-15T16:24:47.783342Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from PIL import Image\nfrom torchvision import transforms\n\n# Image preprocessing\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406],\n                         [0.229, 0.224, 0.225])\n])\n\ndef predict_from_local_path(model, image_path):\n    model.eval()\n    image = Image.open(image_path).convert(\"RGB\")\n    input_tensor = transform(image).unsqueeze(0).to(device)\n\n    with torch.no_grad():\n        output = torch.sigmoid(model(input_tensor))\n        prob = output.item()\n        label = \"Landmark\" if prob > 0.5 else \"Non-Landmark\"\n        print(f\"Prediction: {label} (Confidence: {prob:.4f})\")\n\n    # Display image\n    plt.imshow(image)\n    plt.title(f\"{label} ({prob:.2f})\")\n    plt.axis(\"off\")\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T16:24:47.784991Z","iopub.execute_input":"2025-05-15T16:24:47.785217Z","iopub.status.idle":"2025-05-15T16:24:47.792396Z","shell.execute_reply.started":"2025-05-15T16:24:47.785195Z","shell.execute_reply":"2025-05-15T16:24:47.791751Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predict_from_local_path(model, '/kaggle/input/test-landmark-images/ryan_reynolds.jpg')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T16:30:14.437073Z","iopub.execute_input":"2025-05-15T16:30:14.437361Z","iopub.status.idle":"2025-05-15T16:30:14.539856Z","shell.execute_reply.started":"2025-05-15T16:30:14.437335Z","shell.execute_reply":"2025-05-15T16:30:14.539021Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predict_from_local_path(model, '/kaggle/input/test-landmark-images/Ronaldo.jpg')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T16:38:27.789389Z","iopub.execute_input":"2025-05-15T16:38:27.789731Z","iopub.status.idle":"2025-05-15T16:38:27.975053Z","shell.execute_reply.started":"2025-05-15T16:38:27.789698Z","shell.execute_reply":"2025-05-15T16:38:27.974097Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predict_from_local_path(model, '/kaggle/input/test-landmark-images/guitar.jpg')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T16:40:02.244472Z","iopub.execute_input":"2025-05-15T16:40:02.244835Z","iopub.status.idle":"2025-05-15T16:40:02.316661Z","shell.execute_reply.started":"2025-05-15T16:40:02.244805Z","shell.execute_reply":"2025-05-15T16:40:02.315685Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predict_from_local_path(model, '/kaggle/input/test-landmark-images/whale_shark (2).jpg')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T16:40:15.431706Z","iopub.execute_input":"2025-05-15T16:40:15.432009Z","iopub.status.idle":"2025-05-15T16:40:15.510160Z","shell.execute_reply.started":"2025-05-15T16:40:15.431984Z","shell.execute_reply":"2025-05-15T16:40:15.509365Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predict_from_local_path(model, '/kaggle/input/test-landmark-images/whale_shark (1).jpg')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T16:40:26.425723Z","iopub.execute_input":"2025-05-15T16:40:26.426020Z","iopub.status.idle":"2025-05-15T16:40:26.498562Z","shell.execute_reply.started":"2025-05-15T16:40:26.425995Z","shell.execute_reply":"2025-05-15T16:40:26.497810Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save(model.state_dict(), \"/kaggle/working/mobilenet_landmark.pth\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T16:24:48.131105Z","iopub.execute_input":"2025-05-15T16:24:48.131439Z","iopub.status.idle":"2025-05-15T16:24:48.165154Z","shell.execute_reply.started":"2025-05-15T16:24:48.131407Z","shell.execute_reply":"2025-05-15T16:24:48.164529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torchvision.models as models\nimport torchvision.transforms as transforms\nfrom PIL import Image\n\n# Load model\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = models.mobilenet_v2(pretrained=False)\nmodel.classifier = nn.Sequential(\n    nn.Dropout(0.3),\n    nn.Linear(model.last_channel, 1)  # 1 output for binary classification\n)\nmodel.load_state_dict(torch.load(\"/kaggle/input/mobilenet-landmark-binary-classification/mobilenet_landmark.pth\", map_location=device))\nmodel.to(device)\nmodel.eval()\n\n# Load and preprocess image\nimg_path = \"/kaggle/input/test-landmark-images/whale_shark (2).jpg\"\nimage = Image.open(img_path).convert(\"RGB\")\n\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406],  # ImageNet mean\n                         [0.229, 0.224, 0.225])  # ImageNet std\n])\n\ninput_tensor = transform(image).unsqueeze(0).to(device)\n\n# Inference\nwith torch.no_grad():\n    output = model(input_tensor)\n    prob = torch.sigmoid(output).item()\n    is_landmark = prob >= 0.5\n\n# Print result\nif is_landmark:\n    print(f\"The image is predicted to be a landmark. (Confidence: {prob:.2f})\")\nelse:\n    print(f\"The image is NOT a landmark. (Confidence: {prob:.2f})\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T16:24:48.166435Z","iopub.execute_input":"2025-05-15T16:24:48.166805Z","iopub.status.idle":"2025-05-15T16:24:48.498394Z","shell.execute_reply.started":"2025-05-15T16:24:48.166770Z","shell.execute_reply":"2025-05-15T16:24:48.497652Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import h5py\n\ndef save_model_weights_h5(model, filename=\"/kaggle/working/mobilenet_landmark.h5\"):\n    with h5py.File(filename, 'w') as f:\n        for name, param in model.state_dict().items():\n            f.create_dataset(name, data=param.cpu().numpy())\n\n# Save the model\nsave_model_weights_h5(model)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.applications import InceptionV3\nfrom tensorflow.keras import layers, models\nfrom tensorflow.keras.optimizers import Adam\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix\n\n# Paths to the split datasets\nlandmark_data_dir = '/kaggle/working/landmark_dataset_gldv2'  # Assuming landmark dataset exists\nnon_landmark_data_dir = '/kaggle/working/Imgs'  # Caltech dataset after split\n\n# Create Data Generators\ndatagen = ImageDataGenerator(rescale=1./255, validation_split=0.2)\n\n# Landmark data generator (only using 'train' and 'validation' subsets)\ntrain_landmark_gen = datagen.flow_from_directory(\n    landmark_data_dir,\n    target_size=(224, 224),\n    batch_size=32,\n    class_mode='binary',  # Binary classification\n    subset='training',    # Use 80% of data for training\n    shuffle=True\n)\n\nval_landmark_gen = datagen.flow_from_directory(\n    landmark_data_dir,\n    target_size=(224, 224),\n    batch_size=32,\n    class_mode='binary',  # Binary classification\n    subset='validation',  # Use 20% of data for validation\n    shuffle=True\n)\n\n# Non-Landmark data generator (Caltech dataset - already split into 'train', 'val', 'test')\ntrain_non_landmark_gen = datagen.flow_from_directory(\n    os.path.join(non_landmark_data_dir, 'train'),\n    target_size=(224, 224),\n    batch_size=32,\n    class_mode='binary',  # Binary classification: landmark vs non-landmark\n    shuffle=True\n)\n\nval_non_landmark_gen = datagen.flow_from_directory(\n    os.path.join(non_landmark_data_dir, 'val'),\n    target_size=(224, 224),\n    batch_size=32,\n    class_mode='binary',  # Binary classification: landmark vs non-landmark\n    shuffle=True\n)\n\n# Combine the two datasets for training: landmark vs non-landmark\ntrain_gen = train_landmark_gen\nval_gen = val_landmark_gen","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_model = InceptionV3(weights='imagenet', include_top=False, input_shape=(224, 224, 3))\n\n# Adding custom layers on top of InceptionV3\nx = layers.GlobalAveragePooling2D()(base_model.output)\nx = layers.Dense(128, activation='relu')(x)\nx = layers.Dropout(0.3)(x)  # Dropout for regularization\noutput = layers.Dense(1, activation='sigmoid')(x)  # Sigmoid activation for binary classification\n\nmodel = models.Model(inputs=base_model.input, outputs=output)\n\n# Freeze the base model layers to avoid retraining them\nbase_model.trainable = False\n\n# Compile the model with Adam optimizer\nmodel.compile(optimizer=Adam(learning_rate=1e-4), loss='binary_crossentropy', metrics=['accuracy'])\n\n# Train the model using the combined train generator\nhistory = model.fit(train_gen, validation_data=val_gen, epochs=10)\n\n# Save the model\nmodel.save(\"landmark_detector_inceptionv3_caltech_non_landmark.h5\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Image Transformations","metadata":{}},{"cell_type":"code","source":"import pandas as pd\n\n# Load the train.csv\ntrain_df = pd.read_csv('/kaggle/input/landmark-recognition-2021/train.csv')\n\n# Count the frequency of each landmark_id\nlandmark_counts = train_df['landmark_id'].value_counts().reset_index()\nlandmark_counts.columns = ['landmark_id', 'count']\n\n# Get the landmark_ids ranked 301 to 400\nlandmarks_201_300 = landmark_counts.iloc[200:300]['landmark_id'].tolist()\n\n# Filter the train_df to include only those landmark IDs\nfiltered_df = train_df[train_df['landmark_id'].isin(landmarks_201_300)][['id', 'landmark_id']]\n\n# Save to CSV\nfiltered_df.to_csv('/kaggle/working/image_landmark_201_300.csv', index=False)\n\nprint(\"✅ Saved image_landmark_201_300.csv with image IDs for landmark IDs ranked 301–400.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T15:02:45.991801Z","iopub.execute_input":"2025-05-19T15:02:45.992278Z","iopub.status.idle":"2025-05-19T15:02:47.221987Z","shell.execute_reply.started":"2025-05-19T15:02:45.992242Z","shell.execute_reply":"2025-05-19T15:02:47.220764Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Load the train.csv and 101_200_landmark.csv\ntrain_df = pd.read_csv('/kaggle/input/landmark-recognition-2021/train.csv')\nlandmark_301_400_df = pd.read_csv('/kaggle/working/301_400_landmark.csv')\n\n# Get the list of landmark_ids in the range 101-200\nlandmarks_301_400 = landmark_301_400_df['landmark_id'].tolist()\n\n# Filter the train_df to only include rows where the landmark_id is in the top 201-300 range\nfiltered_train_df = train_df[train_df['landmark_id'].isin(landmarks_301_400)]\n\n# Now we will store the relevant image_id and landmark_id pairs\nresult_df = filtered_train_df[['id', 'landmark_id']]\n\n# Save the resulting DataFrame to a new CSV file\nresult_df.to_csv('/kaggle/working/image_landmark_301_400.csv', index=False)\n\nprint(\"Image ID and Landmark ID pairs for landmarks 301-400 have been saved to /kaggle/working/image_landmark_301_400.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T14:49:28.902620Z","iopub.execute_input":"2025-05-19T14:49:28.903033Z","iopub.status.idle":"2025-05-19T14:49:30.220747Z","shell.execute_reply.started":"2025-05-19T14:49:28.902997Z","shell.execute_reply":"2025-05-19T14:49:30.218844Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Load the train.csv\ntrain_df = pd.read_csv('/kaggle/input/landmark-recognition-2021/train.csv')\n\n# Count the frequency of each landmark_id\nlandmark_counts = train_df['landmark_id'].value_counts().reset_index()\nlandmark_counts.columns = ['landmark_id', 'count']\n\n# Get the landmark_ids ranked 201 to 300\nlandmarks_201_300 = landmark_counts.iloc[200:300]['landmark_id'].reset_index(drop=True)\n\n# Save to CSV\nlandmarks_201_300.to_frame().to_csv('/kaggle/working/201_300_landmark.csv', index=False)\n\nprint(\"✅ Saved 201_300_landmark.csv with landmark IDs ranked 201–300 by frequency.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T14:42:00.768214Z","iopub.execute_input":"2025-05-19T14:42:00.768484Z","iopub.status.idle":"2025-05-19T14:42:03.298528Z","shell.execute_reply.started":"2025-05-19T14:42:00.768456Z","shell.execute_reply":"2025-05-19T14:42:03.297428Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Load the train.csv\ntrain_df = pd.read_csv('/kaggle/input/landmark-recognition-2021/train.csv')\n\n# Count the frequency of each landmark_id\nlandmark_counts = train_df['landmark_id'].value_counts().reset_index()\nlandmark_counts.columns = ['landmark_id', 'count']\n\n# Get the landmark_ids ranked 201 to 300\nlandmarks_301_400 = landmark_counts.iloc[200:300]['landmark_id'].reset_index(drop=True)\n\n# Save to CSV\nlandmarks_301_400.to_frame().to_csv('/kaggle/working/301_400_landmark.csv', index=False)\n\nprint(\"✅ Saved 301_400_landmark.csv with landmark IDs ranked 301–400 by frequency.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## ODIN","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torchvision import models, transforms\nfrom torch.utils.data import DataLoader\nfrom PIL import Image\nimport os\nfrom pathlib import Path\nfrom tqdm import tqdm\n\n# --- SETTINGS ---\nmodel_path = \"/kaggle/input/model-effiecient/best_model_resnet_ver_2-7.pth\"\ntemperature = 10  # ODIN temperature scaling\nepsilon = 0.0014    # Input perturbation magnitude\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nnum_classes = 100\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T15:53:50.930094Z","iopub.execute_input":"2025-05-22T15:53:50.930438Z","iopub.status.idle":"2025-05-22T15:53:50.936443Z","shell.execute_reply.started":"2025-05-22T15:53:50.930411Z","shell.execute_reply":"2025-05-22T15:53:50.935493Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = models.resnet50(pretrained=False)\nin_features = model.fc.in_features","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T15:54:21.113957Z","iopub.execute_input":"2025-05-22T15:54:21.114265Z","iopub.status.idle":"2025-05-22T15:54:21.556352Z","shell.execute_reply.started":"2025-05-22T15:54:21.114225Z","shell.execute_reply":"2025-05-22T15:54:21.555697Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.fc = nn.Sequential(\n    nn.Linear(in_features, 512),\n    nn.ReLU(),\n    nn.Dropout(0.5),\n    nn.Linear(512, 256),\n    nn.ReLU(),\n    nn.Dropout(0.5),\n    nn.Linear(256, num_classes)\n)\n\n# --- LOAD WEIGHTS AND SET TO EVAL ---\nmodel.load_state_dict(torch.load(model_path, map_location=device))\nmodel = model.to(device).eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T15:54:22.865951Z","iopub.execute_input":"2025-05-22T15:54:22.866241Z","iopub.status.idle":"2025-05-22T15:54:23.819988Z","shell.execute_reply.started":"2025-05-22T15:54:22.866216Z","shell.execute_reply":"2025-05-22T15:54:23.819310Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406],\n                         [0.229, 0.224, 0.225])\n])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T15:54:24.852701Z","iopub.execute_input":"2025-05-22T15:54:24.853017Z","iopub.status.idle":"2025-05-22T15:54:24.857760Z","shell.execute_reply.started":"2025-05-22T15:54:24.852987Z","shell.execute_reply":"2025-05-22T15:54:24.856781Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from pathlib import Path\n\nnon_landmark_path = Path(\"/kaggle/working/non_landmark\")\nprint(f\"Exists: {non_landmark_path.exists()}\")\nprint(f\"Is directory: {non_landmark_path.is_dir()}\")\n\n# List first-level subfolders\nprint(\"Subfolders:\", [p.name for p in non_landmark_path.iterdir() if p.is_dir()])\n\n# List some images recursively\nimage_files = list(non_landmark_path.rglob(\"*.*\"))\nprint(f\"Total files under non_landmark: {len(image_files)}\")\nprint(\"Some files:\", image_files[:10])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T15:54:28.141339Z","iopub.execute_input":"2025-05-22T15:54:28.141630Z","iopub.status.idle":"2025-05-22T15:54:28.384016Z","shell.execute_reply.started":"2025-05-22T15:54:28.141606Z","shell.execute_reply":"2025-05-22T15:54:28.383196Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def odin_score(image_tensor, model, temperature, epsilon):\n    image_tensor = image_tensor.unsqueeze(0).to(device)\n    image_tensor.requires_grad = True  # Needed for gradient computation\n\n    model.eval()  # Ensure in eval mode\n\n    # Forward pass\n    logits = model(image_tensor)\n    logits = logits / temperature\n    pred_class = logits.argmax(dim=1)\n\n    # Compute loss\n    loss = F.cross_entropy(logits, pred_class)\n    model.zero_grad()\n    loss.backward()\n\n    # Perturbation\n    gradient = torch.sign(image_tensor.grad.data)\n    perturbed = image_tensor - epsilon * gradient\n    perturbed = torch.clamp(perturbed, 0, 1)\n\n    # Forward with perturbed input\n    with torch.no_grad():\n        logits_perturbed = model(perturbed) / temperature\n        softmax_scores = F.softmax(logits_perturbed, dim=1)\n        score = torch.max(softmax_scores).item()\n\n    return score\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T15:54:31.959683Z","iopub.execute_input":"2025-05-22T15:54:31.959992Z","iopub.status.idle":"2025-05-22T15:54:31.967226Z","shell.execute_reply.started":"2025-05-22T15:54:31.959967Z","shell.execute_reply":"2025-05-22T15:54:31.966325Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_paths = []\nfor ext in [\"*.jpg\", \"*.jpeg\", \"*.JPG\", \"*.JPEG\", \"*.png\"]:\n    image_paths.extend(Path(non_landmark_path).rglob(ext))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T14:51:44.023420Z","iopub.execute_input":"2025-05-22T14:51:44.023730Z","iopub.status.idle":"2025-05-22T14:51:44.397759Z","shell.execute_reply.started":"2025-05-22T14:51:44.023700Z","shell.execute_reply":"2025-05-22T14:51:44.397127Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_images_from_folder(folder_path, transform, max_images=None):\n    image_paths = list(Path(folder_path).rglob(\"*.jpg\"))  # recursive glob to get files in subfolders\n    if max_images:\n        image_paths = image_paths[:max_images]\n    dataset = []\n    for path in image_paths:\n        try:\n            image = Image.open(path).convert(\"RGB\")\n            tensor = transform(image)\n            dataset.append((path.name, tensor))\n        except Exception as e:\n            print(f\"Failed to load {path}: {e}\")\n            continue\n    print(f\"Loaded {len(dataset)} images from {folder_path}\")\n    return dataset\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T14:58:31.468189Z","iopub.execute_input":"2025-05-22T14:58:31.468548Z","iopub.status.idle":"2025-05-22T14:58:31.474345Z","shell.execute_reply.started":"2025-05-22T14:58:31.468506Z","shell.execute_reply":"2025-05-22T14:58:31.473476Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"non_landmark_images = load_images_from_folder(\"/kaggle/working/non_landmark\", transform)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T14:58:33.214648Z","iopub.execute_input":"2025-05-22T14:58:33.214954Z","iopub.status.idle":"2025-05-22T14:59:41.894070Z","shell.execute_reply.started":"2025-05-22T14:58:33.214928Z","shell.execute_reply":"2025-05-22T14:59:41.893030Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Example usage:\nlandmark_images = load_images_from_folder(\"/kaggle/working/landmark\", transform)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T14:59:53.917075Z","iopub.execute_input":"2025-05-22T14:59:53.917422Z","iopub.status.idle":"2025-05-22T15:03:19.578647Z","shell.execute_reply.started":"2025-05-22T14:59:53.917386Z","shell.execute_reply":"2025-05-22T15:03:19.577682Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Score and label\nresults = []\nfor label, image_set in [(\"landmark\", landmark_images), (\"nonlandmark\", non_landmark_images)]:\n    for fname, tensor in tqdm(image_set, desc=f\"Scoring {label} images\"):\n        score = odin_score(tensor, model, temperature, epsilon)\n        results.append({\"filename\": fname, \"score\": score, \"label\": label})\n\n# Save results to CSV\nimport pandas as pd\ndf = pd.DataFrame(results)\ndf.to_csv(\"odin_scores_10.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T15:57:49.406267Z","iopub.execute_input":"2025-05-22T15:57:49.406592Z","iopub.status.idle":"2025-05-22T16:20:23.816344Z","shell.execute_reply.started":"2025-05-22T15:57:49.406566Z","shell.execute_reply":"2025-05-22T16:20:23.815363Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\ndf = pd.read_csv(\"/kaggle/working/odin_scores.csv\")\ndf['label_binary'] = df['label'].map({'landmark': 1, 'nonlandmark': 0})","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T15:47:44.254043Z","iopub.execute_input":"2025-05-22T15:47:44.254351Z","iopub.status.idle":"2025-05-22T15:47:44.296261Z","shell.execute_reply.started":"2025-05-22T15:47:44.254324Z","shell.execute_reply":"2025-05-22T15:47:44.295605Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pip install --upgrade seaborn","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T15:47:19.023870Z","iopub.execute_input":"2025-05-22T15:47:19.024290Z","iopub.status.idle":"2025-05-22T15:47:25.405933Z","shell.execute_reply.started":"2025-05-22T15:47:19.024234Z","shell.execute_reply":"2025-05-22T15:47:25.404756Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sns.distplot(df[df['label'] == 'landmark']['odin_score'], hist=True, kde=True, label='Landmark')\nsns.distplot(df[df['label'] == 'nonlandmark']['odin_score'], hist=True, kde=True, label='Nonlandmark')\nplt.title(\"ODIN Score Distribution\")\nplt.legend()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T15:47:48.742423Z","iopub.execute_input":"2025-05-22T15:47:48.742742Z","iopub.status.idle":"2025-05-22T15:47:48.932194Z","shell.execute_reply.started":"2025-05-22T15:47:48.742717Z","shell.execute_reply":"2025-05-22T15:47:48.930700Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Assuming you have both models: `model_odin` and `model_binary`\n\nfor label, image_set in [(\"landmark\", landmark_images), (\"nonlandmark\", non_landmark_images)]:\n    for fname, tensor in tqdm(image_set, desc=f\"Scoring {label} images\"):\n        odin_score_val = odin_score(tensor.clone(), model_odin, temperature, epsilon)\n\n        with torch.no_grad():\n            binary_input = tensor.unsqueeze(0).to(device)\n            binary_output = model_binary(binary_input)\n            binary_score = torch.sigmoid(binary_output).item()\n\n        results.append({\n            \"filename\": fname,\n            \"label\": label,\n            \"odin_score\": odin_score_val,\n            \"binary_score\": binary_score\n        })","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from pathlib import Path\nfrom PIL import Image\nimport torch.nn.functional as F\nimport torch\n\n# Load only 10 images each\nnon_landmark_images_30 = load_images_from_folder(\"/kaggle/working/non_landmark\", transform, max_images=30)\nlandmark_images_30 = load_images_from_folder(\"/kaggle/working/landmark\", transform, max_images=30)\n\n# Example ODIN scoring function\ndef odin_score(image_tensor, model, temperature=1000, epsilon=0.0014):\n    model.eval()\n    image_tensor = image_tensor.unsqueeze(0).to(device).requires_grad_()\n\n    # Forward pass\n    outputs = model(image_tensor) / temperature\n    max_index = outputs.argmax(dim=1)\n    \n    # Gradient wrt max class\n    loss = F.cross_entropy(outputs, max_index)\n    loss.backward()\n    \n    # Add perturbation\n    gradient = torch.sign(image_tensor.grad.data)\n    perturbed_input = image_tensor - epsilon * gradient\n    perturbed_input = perturbed_input.detach()\n\n    # Forward again\n    with torch.no_grad():\n        output = model(perturbed_input) / temperature\n        softmax_output = F.softmax(output, dim=1)\n        max_softmax = softmax_output.max().item()\n\n    return max_softmax\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T15:52:16.721054Z","iopub.execute_input":"2025-05-22T15:52:16.721394Z","iopub.status.idle":"2025-05-22T15:52:17.522451Z","shell.execute_reply.started":"2025-05-22T15:52:16.721364Z","shell.execute_reply":"2025-05-22T15:52:17.521689Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"temperatures = [10, 100, 1000]\nepsilon = 0.0014  # Typical ODIN epsilon\n\nfor temp in temperatures:\n    print(f\"\\n=== Testing with Temperature: {temp} ===\")\n    print(\"Landmarks:\")\n    for fname, tensor in landmark_images_30:\n        score = odin_score(tensor.clone(), model, temperature=temp, epsilon=epsilon)\n        print(f\"{fname}: {score:.6f}\")\n\n    print(\"\\nNon-landmarks:\")\n    for fname, tensor in non_landmark_images_30:\n        score = odin_score(tensor.clone(), model, temperature=temp, epsilon=epsilon)\n        print(f\"{fname}: {score:.6f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T15:52:33.840747Z","iopub.execute_input":"2025-05-22T15:52:33.841096Z","iopub.status.idle":"2025-05-22T15:52:39.597347Z","shell.execute_reply.started":"2025-05-22T15:52:33.841061Z","shell.execute_reply":"2025-05-22T15:52:39.596472Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/working/odin_scores_10.csv')\ndf_1 = pd.read_csv('/kaggle/working/odin_scores.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T16:29:28.618951Z","iopub.execute_input":"2025-05-22T16:29:28.619272Z","iopub.status.idle":"2025-05-22T16:29:28.682261Z","shell.execute_reply.started":"2025-05-22T16:29:28.619231Z","shell.execute_reply":"2025-05-22T16:29:28.681551Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import roc_curve, roc_auc_score\n\n# Convert label to binary: 1 for landmark, 0 for non-landmark\ndf['label_bin'] = (df['label'] == 'landmark').astype(int)\n\nfpr, tpr, thresholds = roc_curve(df['label_bin'], df['score'])\nauc = roc_auc_score(df['label_bin'], df['score'])\n\nplt.figure(figsize=(8, 6))\nplt.plot(fpr, tpr, label=f'ROC curve (AUC = {auc:.2f})')\nplt.plot([0, 1], [0, 1], 'k--')\nplt.xlabel('False Positive Rate')\nplt.ylabel('True Positive Rate')\nplt.title('ROC Curve')\nplt.legend()\nplt.grid(True)\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T16:30:13.071600Z","iopub.execute_input":"2025-05-22T16:30:13.071927Z","iopub.status.idle":"2025-05-22T16:30:13.250078Z","shell.execute_reply.started":"2025-05-22T16:30:13.071903Z","shell.execute_reply":"2025-05-22T16:30:13.249325Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n# Load CSV\ndf = pd.read_csv('/kaggle/working/odin_scores_10.csv')\n\n# Drop NaNs and invalid scores\ndf = df.dropna(subset=['score'])\n\n# Split and filter scores > 0 for log scale\nlandmark_scores = df[(df['label'] == 'landmark') & (df['score'] > 0)]['score']\nnonlandmark_scores = df[(df['label'] == 'nonlandmark') & (df['score'] > 0)]['score']\n\n# Plot\nplt.figure(figsize=(12, 6))\nsns.kdeplot(landmark_scores, shade=True, label='Landmark', color='blue', linewidth=2)\nsns.kdeplot(nonlandmark_scores, shade=True, label='Non-Landmark', color='red', linewidth=2)\n\n# Add threshold line\nplt.axvline(x=0.02, color='gray', linestyle='--', label='Threshold')\n\n# Log scale for better visibility\nplt.xscale('log')\nplt.xlabel(\"ODIN Score (log scale)\")\nplt.ylabel(\"Density\")\nplt.title(\"ODIN Score Distribution by Class (Log Scale)- Temperature 10\")\nplt.legend()\nplt.grid(True, which=\"both\", linestyle='--', linewidth=0.5)\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T16:41:57.458284Z","iopub.execute_input":"2025-05-22T16:41:57.458650Z","iopub.status.idle":"2025-05-22T16:41:57.849818Z","shell.execute_reply.started":"2025-05-22T16:41:57.458617Z","shell.execute_reply":"2025-05-22T16:41:57.849071Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n# Load CSV\ndf = pd.read_csv('/kaggle/working/odin_scores.csv')\n\n# Drop NaNs and invalid scores\ndf = df.dropna(subset=['score'])\n\n# Split and filter scores > 0 for log scale\nlandmark_scores = df[(df['label'] == 'landmark') & (df['score'] > 0)]['score']\nnonlandmark_scores = df[(df['label'] == 'nonlandmark') & (df['score'] > 0)]['score']\n\n# Plot\nplt.figure(figsize=(12, 6))\nsns.kdeplot(landmark_scores, shade=True, label='Landmark', color='blue', linewidth=2)\nsns.kdeplot(nonlandmark_scores, shade=True, label='Non-Landmark', color='red', linewidth=2)\n\n# Add threshold line\nplt.axvline(x=0.02, color='gray', linestyle='--', label='Threshold')\n\n# Log scale for better visibility\nplt.xscale('log')\nplt.xlabel(\"ODIN Score (log scale)\")\nplt.ylabel(\"Density\")\nplt.title(\"ODIN Score Distribution by Class (Log Scale) Temperature 100\")\nplt.legend()\nplt.grid(True, which=\"both\", linestyle='--', linewidth=0.5)\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T16:42:04.321227Z","iopub.execute_input":"2025-05-22T16:42:04.321588Z","iopub.status.idle":"2025-05-22T16:42:04.839780Z","shell.execute_reply.started":"2025-05-22T16:42:04.321553Z","shell.execute_reply":"2025-05-22T16:42:04.838957Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\n\n# Load CSV\ndf = pd.read_csv('/kaggle/working/odin_scores_10.csv')\n\n# Convert labels to binary\ndf['label_binary'] = df['label'].map({'landmark': 1, 'nonlandmark': 0})\n\n# Convert score to float, and remove invalid values\ndf['score'] = pd.to_numeric(df['score'], errors='coerce')  # convert invalid to NaN\ndf = df.dropna(subset=['score', 'label_binary'])  # drop rows with NaN in score or label\n\n# Check for any infinite or very large values\ndf = df[np.isfinite(df['score'])]  # remove inf/-inf\ndf = df[df['score'] < 1e6]         # remove absurdly large values, just in case\n\n# Proceed to threshold finding\nfrom sklearn.metrics import roc_curve\n\nscores = df['score'].values\nlabels = df['label_binary'].values\n\nfpr, tpr, thresholds = roc_curve(labels, scores)\nyouden_j = tpr - fpr\nbest_index = youden_j.argmax()\noptimal_threshold = thresholds[best_index]\n\nprint(f\"Optimal Threshold (Youden's J): {optimal_threshold:.6f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T16:44:12.454293Z","iopub.execute_input":"2025-05-22T16:44:12.454604Z","iopub.status.idle":"2025-05-22T16:44:12.511989Z","shell.execute_reply.started":"2025-05-22T16:44:12.454578Z","shell.execute_reply":"2025-05-22T16:44:12.511170Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(df[df['score'].isna()])\nprint(df[df['score'] == np.inf])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T16:44:24.782171Z","iopub.execute_input":"2025-05-22T16:44:24.782501Z","iopub.status.idle":"2025-05-22T16:44:24.790710Z","shell.execute_reply.started":"2025-05-22T16:44:24.782473Z","shell.execute_reply":"2025-05-22T16:44:24.789933Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Demo\n","metadata":{}},{"cell_type":"code","source":"from torchvision import transforms\nfrom PIL import Image\nimport torch\n\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n])\n\nimg = Image.open(\"your_test_image.jpg\").convert(\"RGB\")\ninput_tensor = transform(img).unsqueeze(0).cuda()  # Add batch dim\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def odin_score(model, input_tensor, temperature=1000, epsilon=0.0014):\n    input_tensor.requires_grad_()\n\n    # Forward pass\n    output = model(input_tensor)\n    output = output / temperature\n    max_score, pred = output.max(1)\n\n    # Backward on max logit\n    loss = -max_score\n    loss.backward()\n\n    # Add small noise in gradient direction\n    gradient = torch.sign(input_tensor.grad.data)\n    perturbed_input = input_tensor - epsilon * gradient\n    perturbed_input = torch.clamp(perturbed_input, 0, 1)\n\n    # Second forward pass\n    output_perturbed = model(perturbed_input)\n    output_perturbed = output_perturbed / temperature\n    softmax = torch.nn.functional.softmax(output_perturbed, dim=1)\n\n    # Use max softmax probability as ODIN score\n    odin_score = softmax.max(1)[0].item()\n    return odin_score\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"score = odin_score(model, input_tensor)\n\nif score >= 0.022769:\n    print(f\"Image is likely an **In-Distribution (Landmark)** with ODIN score {score:.6f}\")\nelse:\n    print(f\"Image is likely **Out-of-Distribution (Non-Landmark)** with ODIN score {score:.6f}\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}