{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":8078,"databundleVersionId":862231,"sourceType":"competition"},{"sourceId":12134822,"sourceType":"datasetVersion","datasetId":7641927}],"dockerImageVersionId":31011,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nfrom tqdm import tqdm\nfrom sklearn.model_selection import train_test_split\nimport json\n\n# Constants\nALPHA = 0.7\nBETA = 4\nGAMMA = np.log(0.01)\nPATCH_SIZE = 64\nTOP_K_PATCHES = 128\n\ndef patch_quality(patch):\n    Q = 0\n    for channel in range(3):  # R, G, B\n        patch_channel = patch[:, :, channel]\n        mu_c = np.mean(patch_channel)\n        sigma_c = np.std(patch_channel)\n        Q += ALPHA * BETA * (mu_c - mu_c**2) + (1 - ALPHA) * (1 - np.exp(GAMMA * sigma_c))\n    return Q / 3\n\ndef extract_top_k_patches(image, k=TOP_K_PATCHES, patch_size=PATCH_SIZE):\n    h, w, _ = image.shape\n    patches = []\n    qualities = []\n\n    for i in range(0, h - patch_size + 1, patch_size):\n        for j in range(0, w - patch_size + 1, patch_size):\n            patch = image[i:i+patch_size, j:j+patch_size]\n            q = patch_quality(patch)\n            patches.append(patch)\n            qualities.append(q)\n\n    if len(patches) == 0:\n        return []\n\n    sorted_indices = np.argsort(qualities)[::-1]\n    top_indices = sorted_indices[:min(k, len(patches))]\n    top_patches = [patches[i] for i in top_indices]\n\n    if len(top_patches) < k:\n        padding = [np.zeros_like(top_patches[0]) for _ in range(k - len(top_patches))]\n        top_patches.extend(padding)\n\n    return top_patches\n\ndef prepare_dataset_as_images(dataset_path, output_path):\n    for mode in ['train', 'test']:\n        os.makedirs(os.path.join(output_path, mode), exist_ok=True)\n\n    split_dir = os.path.join(output_path, 'splits')\n    os.makedirs(split_dir, exist_ok=True)\n\n    for class_name in sorted(os.listdir(dataset_path)):\n        class_path = os.path.join(dataset_path, class_name)\n        if not os.path.isdir(class_path):\n            continue\n\n        image_files = sorted([f for f in os.listdir(class_path) if f.lower().endswith(('.jpg', '.jpeg', '.png'))])\n        split_file_path = os.path.join(split_dir, f\"{class_name}_split.json\")\n\n        if os.path.exists(split_file_path):\n            with open(split_file_path, 'r') as f:\n                split_data = json.load(f)\n                train_files = split_data['train']\n                test_files = split_data['test']\n        else:\n            train_files, test_files = train_test_split(image_files, test_size=0.2, random_state=42)\n            split_data = {'train': train_files, 'test': test_files}\n            with open(split_file_path, 'w') as f:\n                json.dump(split_data, f, indent=2)\n\n        for mode, file_list in [('train', train_files), ('test', test_files)]:\n            save_dir = os.path.join(output_path, mode, class_name)\n            os.makedirs(save_dir, exist_ok=True)\n\n            for idx, file in enumerate(tqdm(file_list, desc=f\"{mode.upper()} - {class_name}\")):\n                file_path = os.path.join(class_path, file)\n                image = cv2.imread(file_path)\n                if image is None:\n                    continue\n\n                patches = extract_top_k_patches(image)\n                for i, patch in enumerate(patches):\n                    patch_filename = f\"{os.path.splitext(file)[0]}_patch_{i}.jpg\"\n                    patch_path = os.path.join(save_dir, patch_filename)\n                    cv2.imwrite(patch_path, patch)\n\n    print(\"Dataset prepared as image patches with persistent train/test splits!\")\n\n# Example usage for Kaggle\ndataset_path = '/kaggle/input/sp-society-camera-model-identification/train/train/'  # or wherever your Kaggle dataset is mounted\noutput_path = '/kaggle/working/processed_dataset'\n\nprepare_dataset_as_images(dataset_path, output_path)\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-20T15:57:55.112544Z","iopub.execute_input":"2025-05-20T15:57:55.112819Z","iopub.status.idle":"2025-05-20T16:24:13.407199Z","shell.execute_reply.started":"2025-05-20T15:57:55.112797Z","shell.execute_reply":"2025-05-20T16:24:13.406405Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Zip file of train test split**","metadata":{}},{"cell_type":"code","source":"import shutil\n\n# Define the source folder and output zip path\nsource_folder = '/kaggle/working'\nzip_filename = '/kaggle/working/processed_dataset.zip'\n\n# Create a zip file of the entire working directory\nshutil.make_archive(base_name=zip_filename.replace('.zip', ''), format='zip', root_dir=source_folder)\n\nprint(f\"Zipped dataset saved to: {zip_filename}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T16:34:26.645746Z","iopub.execute_input":"2025-05-20T16:34:26.646022Z","iopub.status.idle":"2025-05-20T16:35:23.095354Z","shell.execute_reply.started":"2025-05-20T16:34:26.646002Z","shell.execute_reply":"2025-05-20T16:35:23.094354Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **ResNet50**","metadata":{}},{"cell_type":"code","source":"import os\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import DataLoader\nfrom torchvision import datasets, models, transforms\nimport numpy as np\n\n# Constants\nNUM_CLASSES = 10\nBATCH_SIZE = 128\nLEARNING_RATE = 0.0001\nEPOCHS = 20\nFEATURE_SAVE_PATH = '/kaggle/working/features_rn50.npy'\nLABEL_SAVE_PATH = '/kaggle/working/true_labels_rn50.npy'\nPREDICTION_SAVE_PATH = '/kaggle/working/predictions_rn50.npy'\n\n# Dataset path\ndataset_path = '/kaggle/working/processed_dataset'\n\n# Transforms\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomRotation(15),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                         std=[0.229, 0.224, 0.225]),\n])\n\n# Datasets and Dataloaders\ntrain_dataset = datasets.ImageFolder(root=os.path.join(dataset_path, 'train'), transform=transform)\ntest_dataset = datasets.ImageFolder(root=os.path.join(dataset_path, 'test'), transform=transform)\ntrain_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2)\ntest_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=2)\n\n# Print class mapping\nprint(\"Class to index mapping:\", train_dataset.class_to_idx)\n\n# Device configuration\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(\"Using device:\", device)\n\n# ResNet50 Model for classification + feature extraction\nclass ResNet50FeatureExtractor(nn.Module):\n    def __init__(self, num_classes=10):\n        super(ResNet50FeatureExtractor, self).__init__()\n        self.resnet = models.resnet50(pretrained=True)\n        self.feature_extractor = nn.Sequential(*list(self.resnet.children())[:-1])  # exclude final fc\n        in_features = self.resnet.fc.in_features\n        self.classifier = nn.Linear(in_features, num_classes)\n\n    def forward(self, x):\n        features = self.feature_extractor(x)  # [B, 2048, 1, 1]\n        features = features.view(features.size(0), -1)  # flatten to [B, 2048]\n        logits = self.classifier(features)\n        return logits, features\n\nmodel = ResNet50FeatureExtractor(num_classes=NUM_CLASSES).to(device)\n\n# Loss and optimizer\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE)\n\n# Training loop\ndef train_model():\n    best_acc = 0.0\n    for epoch in range(EPOCHS):\n        model.train()\n        running_loss = 0.0\n        correct, total = 0, 0\n\n        for images, labels in train_loader:\n            images, labels = images.to(device), labels.to(device)\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            _, preds = torch.max(outputs, 1)\n            correct += (preds == labels).sum().item()\n            total += labels.size(0)\n\n        acc = correct / total\n        print(f\"Epoch [{epoch+1}/{EPOCHS}] - Loss: {running_loss:.4f}, Accuracy: {acc:.4f}\")\n\n        # Evaluation after each epoch\n        test_acc = evaluate_model()\n        if test_acc > best_acc:\n            best_acc = test_acc\n            torch.save(model.state_dict(), '/kaggle/working/best_resnet50_rgb.pth')\n\n# Evaluation and feature saving\ndef evaluate_model(save_results=False):\n    model.eval()\n    all_preds, all_labels, all_features = [], [], []\n\n    with torch.no_grad():\n        for images, labels in test_loader:\n            images, labels = images.to(device), labels.to(device)\n            outputs, features = model(images)\n            _, preds = torch.max(outputs, 1)\n\n            all_preds.extend(preds.cpu().numpy())\n            all_labels.extend(labels.cpu().numpy())\n            all_features.append(features.cpu().numpy())\n\n    all_features = np.concatenate(all_features, axis=0)\n    acc = np.mean(np.array(all_preds) == np.array(all_labels))\n    print(f\"Test Accuracy: {acc:.4f}\")\n\n    if save_results:\n        np.save(FEATURE_SAVE_PATH, all_features)\n        np.save(LABEL_SAVE_PATH, np.array(all_labels))\n        np.save(PREDICTION_SAVE_PATH, np.array(all_preds))\n\n    return acc\n\n# Run training and save features\ntrain_model()\nevaluate_model(save_results=True)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T03:59:12.996378Z","iopub.execute_input":"2025-06-12T03:59:12.997021Z","iopub.status.idle":"2025-06-12T03:59:39.017455Z","shell.execute_reply.started":"2025-06-12T03:59:12.996997Z","shell.execute_reply":"2025-06-12T03:59:39.016328Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom sklearn.svm import SVC\nfrom sklearn.neighbors import KNeighborsClassifier\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.metrics import accuracy_score\nfrom scipy.stats import mode\n\n# Load ResNet50 features and labels\nfeatures = np.load('/kaggle/working/features_rn50.npy')\ntrue_labels = np.load('/kaggle/working/true_labels_rn50.npy')\n\n# Scale features\nscaler = StandardScaler()\nfeatures_scaled = scaler.fit_transform(features)\n\n# Initialize classifiers\nsvm = SVC(kernel='rbf', probability=True, random_state=42)\nknn = KNeighborsClassifier(n_neighbors=5)\nrf = RandomForestClassifier(n_estimators=100, random_state=42)\n\n# Train classifiers on ResNet50 features\nsvm_preds = svm.fit(features_scaled, true_labels).predict(features_scaled)\nknn_preds = knn.fit(features_scaled, true_labels).predict(features_scaled)\nrf_preds = rf.fit(features_scaled, true_labels).predict(features_scaled)\n\n# Ensemble majority voting\nvotes = np.vstack([svm_preds, knn_preds, rf_preds]).T\nensemble_preds, _ = mode(votes, axis=1, keepdims=True)\nensemble_preds = ensemble_preds.flatten()\n\n# Save accuracies for plotting later\nsvm_acc = accuracy_score(true_labels, svm_preds) * 100\nknn_acc = accuracy_score(true_labels, knn_preds) * 100\nrf_acc = accuracy_score(true_labels, rf_preds) * 100\nensemble_acc = accuracy_score(true_labels, ensemble_preds) * 100\n\nprint(f\"SVM Accuracy: {svm_acc:.2f}%\")\nprint(f\"KNN Accuracy: {knn_acc:.2f}%\")\nprint(f\"Random Forest Accuracy: {rf_acc:.2f}%\")\nprint(f\"Ensemble Accuracy: {ensemble_acc:.2f}%\")\n\n# Save results to CSV\ndf = pd.DataFrame({\n    'SVM': svm_preds,\n    'KNN': knn_preds,\n    'RF': rf_preds,\n    'Ensemble': ensemble_preds,\n    'True_Label': true_labels\n})\ndf.to_csv('/kaggle/working/resnet50_classifier_outputs.csv', index=False)\nprint(\"Saved ResNet50 classifier predictions and ensemble to /kaggle/working/resnet50_classifier_outputs.csv\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T09:35:06.235601Z","iopub.execute_input":"2025-06-02T09:35:06.236171Z","iopub.status.idle":"2025-06-02T10:03:26.592184Z","shell.execute_reply.started":"2025-06-02T09:35:06.236144Z","shell.execute_reply":"2025-06-02T10:03:26.591346Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **DenseNet121**","metadata":{}},{"cell_type":"code","source":"import os\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import DataLoader\nfrom torchvision import datasets, models, transforms\nimport numpy as np\nfrom torch.cuda.amp import autocast, GradScaler\n\n# Constants\nNUM_CLASSES = 10\nBATCH_SIZE = 64\nLEARNING_RATE = 0.0001\nEPOCHS = 20  # Try to reach at least 10\nACCUMULATION_STEPS = 2  # Simulates effective batch size = 8\nFEATURE_SAVE_PATH = '/kaggle/working/features_densenet121.npy'\nLABEL_SAVE_PATH = '/kaggle/working/true_labels_densenet121.npy'\nPREDICTION_SAVE_PATH = '/kaggle/working/predictions_densenet121.npy'\n\n# Dataset path\ndataset_path = '/kaggle/working/processed_dataset'\n\n# Transforms (simplified for speed)\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.RandomHorizontalFlip(),  # Light augmentation\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                         std=[0.229, 0.224, 0.225]),\n])\n\n# Datasets and Dataloaders\ntrain_dataset = datasets.ImageFolder(root=os.path.join(dataset_path, 'train'), transform=transform)\ntest_dataset = datasets.ImageFolder(root=os.path.join(dataset_path, 'test'), transform=transform)\ntrain_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2, pin_memory=True)\ntest_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=2, pin_memory=True)\n\nprint(\"Class to index mapping:\", train_dataset.class_to_idx)\n\n# Device\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(\"Using device:\", device)\n\n# DenseNet121 model with feature extraction\nclass DenseNet121FeatureExtractor(nn.Module):\n    def __init__(self, num_classes=10):\n        super(DenseNet121FeatureExtractor, self).__init__()\n        self.densenet = models.densenet121(pretrained=True)\n        self.features_extractor = self.densenet.features\n        self.pooling = nn.AdaptiveAvgPool2d((1, 1))\n        in_features = self.densenet.classifier.in_features\n        self.classifier = nn.Linear(in_features, num_classes)\n\n    def forward(self, x):\n        features = self.features_extractor(x)\n        features = self.pooling(features)\n        features = torch.flatten(features, 1)\n        logits = self.classifier(features)\n        return logits, features\n\nmodel = DenseNet121FeatureExtractor(num_classes=NUM_CLASSES).to(device)\n\n# Loss, optimizer, scaler for AMP\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE)\nscaler = GradScaler()\n\n# Train\ndef train_model():\n    best_acc = 0.0\n    for epoch in range(EPOCHS):\n        model.train()\n        running_loss = 0.0\n        correct, total = 0, 0\n\n        optimizer.zero_grad()\n\n        for i, (images, labels) in enumerate(train_loader):\n            images, labels = images.to(device), labels.to(device)\n\n            with autocast():\n                outputs, _ = model(images)\n                loss = criterion(outputs, labels)\n                loss = loss / ACCUMULATION_STEPS\n\n            scaler.scale(loss).backward()\n\n            if (i + 1) % ACCUMULATION_STEPS == 0 or (i + 1) == len(train_loader):\n                torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=5.0)\n                scaler.step(optimizer)\n                scaler.update()\n                optimizer.zero_grad()\n\n            running_loss += loss.item() * ACCUMULATION_STEPS\n            _, preds = torch.max(outputs, 1)\n            correct += (preds == labels).sum().item()\n            total += labels.size(0)\n\n        acc = correct / total\n        print(f\"Epoch [{epoch+1}/{EPOCHS}] - Loss: {running_loss:.4f}, Accuracy: {acc:.4f}\")\n\n        test_acc = evaluate_model()\n        if test_acc > best_acc:\n            best_acc = test_acc\n            torch.save(model.state_dict(), '/kaggle/working/best_densenet121_rgb.pth')\n\n# Evaluation and feature saving\ndef evaluate_model(save_results=False):\n    model.eval()\n    all_preds, all_labels, all_features = [], [], []\n\n    with torch.no_grad():\n        for images, labels in test_loader:\n            images, labels = images.to(device), labels.to(device)\n            outputs, features = model(images)\n            _, preds = torch.max(outputs, 1)\n\n            all_preds.extend(preds.cpu().numpy())\n            all_labels.extend(labels.cpu().numpy())\n            all_features.append(features.cpu().numpy())\n\n    all_features = np.concatenate(all_features, axis=0)\n    acc = np.mean(np.array(all_preds) == np.array(all_labels))\n    print(f\"Test Accuracy: {acc:.4f}\")\n\n    if save_results:\n        np.save(FEATURE_SAVE_PATH, all_features)\n        np.save(LABEL_SAVE_PATH, np.array(all_labels))\n        np.save(PREDICTION_SAVE_PATH, np.array(all_preds))\n\n    return acc\n\n# Run\ntrain_model()\nevaluate_model(save_results=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T07:07:54.962137Z","iopub.execute_input":"2025-05-24T07:07:54.962707Z","iopub.status.idle":"2025-05-24T14:47:02.408661Z","shell.execute_reply.started":"2025-05-24T07:07:54.962682Z","shell.execute_reply":"2025-05-24T14:47:02.407888Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom sklearn.svm import SVC\nfrom sklearn.neighbors import KNeighborsClassifier\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.metrics import accuracy_score\nfrom scipy.stats import mode\n\n# Load ResNet50 features and labels\nfeatures = np.load('/kaggle/working/features_densenet121.npy')\ntrue_labels = np.load('/kaggle/working/true_labels_densenet121.npy')\n\n# Scale features\nscaler = StandardScaler()\nfeatures_scaled = scaler.fit_transform(features)\n\n# Initialize classifiers\nsvm = SVC(kernel='rbf', probability=True, random_state=42)\nknn = KNeighborsClassifier(n_neighbors=5)\nrf = RandomForestClassifier(n_estimators=100, random_state=42)\n\n# Train classifiers on ResNet50 features\nsvm_preds = svm.fit(features_scaled, true_labels).predict(features_scaled)\nknn_preds = knn.fit(features_scaled, true_labels).predict(features_scaled)\nrf_preds = rf.fit(features_scaled, true_labels).predict(features_scaled)\n\n# Ensemble majority voting\nvotes = np.vstack([svm_preds, knn_preds, rf_preds]).T\nensemble_preds, _ = mode(votes, axis=1, keepdims=True)\nensemble_preds = ensemble_preds.flatten()\n\n# Save accuracies for plotting later\nsvm_acc = accuracy_score(true_labels, svm_preds) * 100\nknn_acc = accuracy_score(true_labels, knn_preds) * 100\nrf_acc = accuracy_score(true_labels, rf_preds) * 100\nensemble_acc = accuracy_score(true_labels, ensemble_preds) * 100\n\nprint(f\"SVM Accuracy: {svm_acc:.2f}%\")\nprint(f\"KNN Accuracy: {knn_acc:.2f}%\")\nprint(f\"Random Forest Accuracy: {rf_acc:.2f}%\")\nprint(f\"Ensemble Accuracy: {ensemble_acc:.2f}%\")\n\n# Save results to CSV\ndf = pd.DataFrame({\n    'SVM': svm_preds,\n    'KNN': knn_preds,\n    'RF': rf_preds,\n    'Ensemble': ensemble_preds,\n    'True_Label': true_labels\n})\ndf.to_csv('/kaggle/working/densenet121_classifier_outputs.csv', index=False)\nprint(\"Saved densenet121 classifier predictions and ensemble to /kaggle/working/densenet121_classifier_outputs.csv\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T13:19:18.479356Z","iopub.execute_input":"2025-06-02T13:19:18.479652Z","iopub.status.idle":"2025-06-02T13:35:53.502940Z","shell.execute_reply.started":"2025-06-02T13:19:18.479631Z","shell.execute_reply":"2025-06-02T13:35:53.502099Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\n# Load individual feature sets\nresnet_features = np.load('/kaggle/input/features-rn50new-npy/features_rn50.npy')#np.load('/kaggle/working/features_rn50.npy')\ndensenet_features = np.load('/kaggle/working/features_densenet121.npy')\n\n# Concatenate features\nfused_features = np.concatenate([resnet_features, densenet_features], axis=1)\n\n# Save fused features\nnp.save('/kaggle/working/fused_features.npy', fused_features)\nprint(\"✅ Fused features saved to /kaggle/working/fused_features.npy\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T04:00:32.531850Z","iopub.execute_input":"2025-06-12T04:00:32.532643Z","iopub.status.idle":"2025-06-12T04:00:37.577857Z","shell.execute_reply.started":"2025-06-12T04:00:32.532613Z","shell.execute_reply":"2025-06-12T04:00:37.577038Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nfrom sklearn.svm import SVC\nfrom sklearn.neighbors import KNeighborsClassifier\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.metrics import accuracy_score\n\n# Load fused features\nfused_features = np.load('/kaggle/working/fused_features.npy', allow_pickle=True) \\\n    if os.path.exists('/kaggle/working/fused_features.npy') else \\\n    np.concatenate([\n        np.load('/kaggle/working/features_rn50.npy'),\n        np.load('/kaggle/working/features_densenet121.npy')\n    ], axis=1)\n\ntrue_labels = np.load('/kaggle/working/true_labels_rn50.npy')\n\n# Scale features\nscaler = StandardScaler()\nfused_features = scaler.fit_transform(fused_features)\n\n# Initialize classifiers\nsvm = SVC(kernel='rbf', probability=True, random_state=42)\nknn = KNeighborsClassifier(n_neighbors=5)\nrf = RandomForestClassifier(n_estimators=100, random_state=42)\n\n# Train and predict\nsvm_preds = svm.fit(fused_features, true_labels).predict(fused_features)\nknn_preds = knn.fit(fused_features, true_labels).predict(fused_features)\nrf_preds = rf.fit(fused_features, true_labels).predict(fused_features)\n\n# Accuracy\nsvm_acc = accuracy_score(true_labels, svm_preds) * 100\nknn_acc = accuracy_score(true_labels, knn_preds) * 100\nrf_acc = accuracy_score(true_labels, rf_preds) * 100\n\n# Print\nprint(f\"✅ SVM Accuracy: {svm_acc:.2f}%\")\nprint(f\"✅ KNN Accuracy: {knn_acc:.2f}%\")\nprint(f\"✅ Random Forest Accuracy: {rf_acc:.2f}%\")\n\n# Save predictions\ndf = pd.DataFrame({\n    'SVM': svm_preds,\n    'KNN': knn_preds,\n    'RF': rf_preds,\n    'True_Label': true_labels\n})\ndf.to_csv('/kaggle/working/classifier_outputs.csv', index=False)\nprint(\" Saved classifier predictions to /kaggle/working/classifier_outputs.csv\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T04:20:54.663830Z","iopub.execute_input":"2025-06-12T04:20:54.664311Z","iopub.status.idle":"2025-06-12T04:59:59.211767Z","shell.execute_reply.started":"2025-06-12T04:20:54.664289Z","shell.execute_reply":"2025-06-12T04:59:59.210984Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nfrom scipy.stats import mode\nfrom sklearn.metrics import accuracy_score\n\n# Load predictions\ndf = pd.read_csv('/kaggle/working/classifier_outputs.csv')\n\n# Compute majority vote\nvotes = df[['SVM', 'KNN', 'RF']].values\nmajority_preds, _ = mode(votes, axis=1, keepdims=True)\nmajority_preds = majority_preds.flatten()\n\n# Accuracy\ntrue_labels = df['True_Label'].values\nensemble_acc = accuracy_score(true_labels, majority_preds) * 100\nprint(f\"🏁 Ensemble (majority voting) Accuracy: {ensemble_acc:.2f}%\")\n\n# Save ensemble results\ndf['Ensemble'] = majority_preds\ndf.to_csv('/kaggle/working/ensemble_result.csv', index=False)\nprint(\"📁 Saved ensemble results to /kaggle/working/ensemble_result.csv\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T05:11:39.594483Z","iopub.execute_input":"2025-06-12T05:11:39.595074Z","iopub.status.idle":"2025-06-12T05:11:42.029773Z","shell.execute_reply.started":"2025-06-12T05:11:39.595047Z","shell.execute_reply":"2025-06-12T05:11:42.029114Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 📌 Evaluation Metrics for Ensemble (Majority Voting)\n\nfrom sklearn.metrics import precision_score, f1_score\n\n# True labels and predictions\ntrue_labels = df['True_Label'].values\nensemble_preds = df['Ensemble'].values\n\n# Compute macro-averaged precision and F1-score\nensemble_precision = precision_score(true_labels, ensemble_preds, average='macro')\nensemble_f1 = f1_score(true_labels, ensemble_preds, average='macro')\n\n# Print results\nprint(f\"🎯 Ensemble (majority voting) Precision (macro): {ensemble_precision * 100:.2f}%\")\nprint(f\"📊 Ensemble (majority voting) F1 Score (macro): {ensemble_f1 * 100:.2f}%\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T05:11:59.678038Z","iopub.execute_input":"2025-06-12T05:11:59.678709Z","iopub.status.idle":"2025-06-12T05:11:59.704332Z","shell.execute_reply.started":"2025-06-12T05:11:59.678678Z","shell.execute_reply":"2025-06-12T05:11:59.703683Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import precision_score, recall_score\n\n# === Load CSV file ===\ndf = pd.read_csv('/kaggle/working/ensemble_result.csv')\n\n# === Get true labels ===\ny_true = df['True_Label'].values\n\n# === Define models ===\nmodels = ['SVM', 'KNN', 'RF', 'Ensemble']\nprecisions = []\nrecalls = []\n\n# === Compute metrics ===\nfor model in models:\n    y_pred = df[model].values\n    precisions.append(precision_score(y_true, y_pred, average='macro') * 100)\n    recalls.append(recall_score(y_true, y_pred, average='macro') * 100)\n\n# === Labeling function ===\ndef add_labels(bars):\n    for bar in bars:\n        height = bar.get_height()\n        plt.text(bar.get_x() + bar.get_width() / 2, height + 0.5,\n                 f'{height:.2f}%', ha='center', va='bottom', fontsize=10)\n\n# === Plot Precision ===\nplt.figure(figsize=(8, 5))\nbars1 = plt.bar(models, precisions, color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'])\nadd_labels(bars1)\nplt.title('Macro Precision of Classifiers')\nplt.ylabel('Precision (%)')\nplt.ylim(0, 105)\nplt.grid(axis='y', linestyle='--', alpha=0.6)\nplt.show()\n\n# === Plot Recall ===\nplt.figure(figsize=(8, 5))\nbars2 = plt.bar(models, recalls, color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'])\nadd_labels(bars2)\nplt.title('Macro Recall of Classifiers')\nplt.ylabel('Recall (%)')\nplt.ylim(0, 105)\nplt.grid(axis='y', linestyle='--', alpha=0.6)\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T05:31:13.511424Z","iopub.execute_input":"2025-06-12T05:31:13.511726Z","iopub.status.idle":"2025-06-12T05:31:13.807902Z","shell.execute_reply.started":"2025-06-12T05:31:13.511706Z","shell.execute_reply":"2025-06-12T05:31:13.807267Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **ResNet50 confusion matrix** ","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\nimport seaborn as sns\n\n# Load saved predictions and labels\npredictions = np.load('/kaggle/working/predictions_rn50.npy')\ntrue_labels = np.load('/kaggle/working/true_labels_rn50.npy')\n\n# Compute confusion matrix\ncm = confusion_matrix(true_labels, predictions)\n\n# Optional: Normalize the confusion matrix\ncm_normalized = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n\n# Plot\nplt.figure(figsize=(8, 6))\nsns.heatmap(cm_normalized, annot=True, fmt='.2f', cmap='Blues', xticklabels=range(10), yticklabels=range(10))\nplt.title(\"Normalized Confusion Matrix - ResNet50\")\nplt.xlabel(\"Predicted Labels\")\nplt.ylabel(\"True Labels\")\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T08:21:08.804239Z","iopub.execute_input":"2025-06-02T08:21:08.805146Z","iopub.status.idle":"2025-06-02T08:21:09.182123Z","shell.execute_reply.started":"2025-06-02T08:21:08.805118Z","shell.execute_reply":"2025-06-02T08:21:09.181386Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nfrom sklearn.metrics import accuracy_score\nimport matplotlib.pyplot as plt\n\n# Load predictions from CSV\ndf = pd.read_csv('/kaggle/working/resnet50_classifier_outputs.csv')\n\n# Extract predictions and true labels\ntrue_labels = df['True_Label'].values\nsvm_preds = df['SVM'].values\nknn_preds = df['KNN'].values\nrf_preds = df['RF'].values\nensemble_preds = df['Ensemble'].values\n\n# Compute accuracies\nsvm_acc = accuracy_score(true_labels, svm_preds) * 100\nknn_acc = accuracy_score(true_labels, knn_preds) * 100\nrf_acc = accuracy_score(true_labels, rf_preds) * 100\nensemble_acc = accuracy_score(true_labels, ensemble_preds) * 100\n\n# Plot\naccuracies = {\n    'SVM': svm_acc,\n    'KNN': knn_acc,\n    'Random Forest': rf_acc,\n    'Ensemble': ensemble_acc\n}\n\nplt.figure(figsize=(10,6))\nbars = plt.bar(accuracies.keys(), accuracies.values(), color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'])\nplt.ylim(0, 105)\nplt.ylabel('Accuracy (%)')\nplt.title('ResNet50 ML Model Accuracy Comparison')\nplt.grid(axis='y', linestyle='--', alpha=0.7)\n\nfor bar in bars:\n    yval = bar.get_height()\n    plt.text(bar.get_x() + bar.get_width()/2, yval + 1, f'{yval:.2f}%', ha='center', va='bottom')\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T13:08:33.755338Z","iopub.execute_input":"2025-06-02T13:08:33.755857Z","iopub.status.idle":"2025-06-02T13:08:34.080621Z","shell.execute_reply.started":"2025-06-02T13:08:33.755835Z","shell.execute_reply":"2025-06-02T13:08:34.079779Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision import datasets, transforms\n\n# Define a basic transform just to initialize the dataset (no actual image loading needed here)\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n])\n\n# Re-initialize test dataset\ntest_dataset = datasets.ImageFolder(root='/kaggle/working/processed_dataset/test', transform=transform)\n\n# Get class-to-index mapping\nclass_to_idx = test_dataset.class_to_idx\n\n# Reverse mapping\nidx_to_class = {v: k for k, v in class_to_idx.items()}\n\n# Print the mapping\nprint(\"Class Index to Name Mapping:\")\nfor idx in sorted(idx_to_class):\n    print(f\"{idx}: {idx_to_class[idx]}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T08:20:40.436140Z","iopub.execute_input":"2025-06-02T08:20:40.436403Z","iopub.status.idle":"2025-06-02T08:20:47.504752Z","shell.execute_reply.started":"2025-06-02T08:20:40.436383Z","shell.execute_reply":"2025-06-02T08:20:47.504147Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **DenseNet121 confusion matrix** ","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\nimport seaborn as sns\n\n# Load saved predictions and labels\npredictions = np.load('/kaggle/working/predictions_densenet121.npy')\ntrue_labels = np.load('/kaggle/working/true_labels_densenet121.npy')\n\n# Compute confusion matrix\ncm = confusion_matrix(true_labels, predictions)\n\n# Optional: Normalize the confusion matrix\ncm_normalized = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n\n# Plot\nplt.figure(figsize=(8, 6))\nsns.heatmap(cm_normalized, annot=True, fmt='.2f', cmap='Blues', xticklabels=range(10), yticklabels=range(10))\nplt.title(\"Normalized Confusion Matrix - DenseNet121\")\nplt.xlabel(\"Predicted Labels\")\nplt.ylabel(\"True Labels\")\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T08:27:32.548317Z","iopub.execute_input":"2025-06-02T08:27:32.548670Z","iopub.status.idle":"2025-06-02T08:27:32.968070Z","shell.execute_reply.started":"2025-06-02T08:27:32.548640Z","shell.execute_reply":"2025-06-02T08:27:32.967194Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nfrom sklearn.metrics import accuracy_score\nimport matplotlib.pyplot as plt\n\n# Load predictions from CSV\ndf = pd.read_csv('/kaggle/working/densenet121_classifier_outputs.csv')\n\n# Extract predictions and true labels\ntrue_labels = df['True_Label'].values\nsvm_preds = df['SVM'].values\nknn_preds = df['KNN'].values\nrf_preds = df['RF'].values\nensemble_preds = df['Ensemble'].values\n\n# Compute accuracies\nsvm_acc = accuracy_score(true_labels, svm_preds) * 100\nknn_acc = accuracy_score(true_labels, knn_preds) * 100\nrf_acc = accuracy_score(true_labels, rf_preds) * 100\nensemble_acc = accuracy_score(true_labels, ensemble_preds) * 100\n\n# Plot\naccuracies = {\n    'SVM': svm_acc,\n    'KNN': knn_acc,\n    'Random Forest': rf_acc,\n    'Ensemble': ensemble_acc\n}\n\nplt.figure(figsize=(10,6))\nbars = plt.bar(accuracies.keys(), accuracies.values(), color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'])\nplt.ylim(0, 105)\nplt.ylabel('Accuracy (%)')\nplt.title('densenet121 ML Model Accuracy Comparison')\nplt.grid(axis='y', linestyle='--', alpha=0.7)\n\nfor bar in bars:\n    yval = bar.get_height()\n    plt.text(bar.get_x() + bar.get_width()/2, yval + 1, f'{yval:.2f}%', ha='center', va='bottom')\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T13:48:20.936792Z","iopub.execute_input":"2025-06-02T13:48:20.937325Z","iopub.status.idle":"2025-06-02T13:48:21.099381Z","shell.execute_reply.started":"2025-06-02T13:48:20.937299Z","shell.execute_reply":"2025-06-02T13:48:21.098591Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Ensemble learning Confusion matrix**","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport numpy as np\n\ntrue_labels = df['True_Label'].values\nensemble_preds = df['Ensemble'].values\n\ncm = confusion_matrix(true_labels, ensemble_preds)\nprint(\"Confusion matrix shape:\", cm.shape)  # Should be (10,10) for 10 classes\n\n# Plot confusion matrix heatmap\nplt.figure(figsize=(10,7))\nsns.heatmap(cm, annot=True, fmt='d', cmap='Blues')\nplt.xlabel('Predicted')\nplt.ylabel('True')\nplt.title('Confusion Matrix for Ensemble')\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T08:41:04.697839Z","iopub.execute_input":"2025-06-02T08:41:04.698152Z","iopub.status.idle":"2025-06-02T08:41:05.045762Z","shell.execute_reply.started":"2025-06-02T08:41:04.698129Z","shell.execute_reply":"2025-06-02T08:41:05.045036Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport numpy as np\n\ntrue_labels = df['True_Label'].values\nensemble_preds = df['Ensemble'].values\n\ncm = confusion_matrix(true_labels, ensemble_preds)\nprint(\"Confusion matrix shape:\", cm.shape)  # Should be (10,10)\n\n# Normalize confusion matrix rows to percentages\ncm_percent = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] * 100\n\n# Plot confusion matrix heatmap with percentages\nplt.figure(figsize=(10,7))\nsns.heatmap(cm_percent, annot=True, fmt='.2f', cmap='Blues')\nplt.xlabel('Predicted')\nplt.ylabel('True')\nplt.title('Confusion Matrix for Ensemble (Percentage)')\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T08:44:57.255290Z","iopub.execute_input":"2025-06-02T08:44:57.255582Z","iopub.status.idle":"2025-06-02T08:44:57.845052Z","shell.execute_reply.started":"2025-06-02T08:44:57.255560Z","shell.execute_reply":"2025-06-02T08:44:57.844319Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import accuracy_score\n\n# Load saved predictions with ensemble\ndf = pd.read_csv('/kaggle/working/ensemble_result.csv')\n\n# Extract true labels and classifier predictions\ntrue_labels = df['True_Label'].values\nsvm_preds = df['SVM'].values\nknn_preds = df['KNN'].values\nrf_preds = df['RF'].values\nensemble_preds = df['Ensemble'].values\n\n# Calculate accuracies\nsvm_acc = accuracy_score(true_labels, svm_preds) * 100\nknn_acc = accuracy_score(true_labels, knn_preds) * 100\nrf_acc = accuracy_score(true_labels, rf_preds) * 100\nensemble_acc = accuracy_score(true_labels, ensemble_preds) * 100\n\n# Prepare data for bar chart\naccuracies = {\n    'SVM': svm_acc,\n    'KNN': knn_acc,\n    'Random Forest': rf_acc,\n    'Ensemble': ensemble_acc\n}\n\n# Plot\nplt.figure(figsize=(10,6))\nbars = plt.bar(accuracies.keys(), accuracies.values(), color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'])\nplt.ylim(0, 105)\nplt.ylabel('Accuracy (%)')\nplt.title('Fusion Model: ML Classifiers vs Ensemble Accuracy')\nplt.grid(axis='y', linestyle='--', alpha=0.7)\n\n# Add accuracy labels\nfor bar in bars:\n    yval = bar.get_height()\n    plt.text(bar.get_x() + bar.get_width()/2, yval + 1, f'{yval:.2f}%', ha='center', va='bottom')\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T13:16:59.138507Z","iopub.execute_input":"2025-06-02T13:16:59.138970Z","iopub.status.idle":"2025-06-02T13:16:59.323791Z","shell.execute_reply.started":"2025-06-02T13:16:59.138946Z","shell.execute_reply":"2025-06-02T13:16:59.323132Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Wavelet Feature Extraction**","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pywt\nfrom sklearn.decomposition import PCA\nfrom sklearn.preprocessing import StandardScaler\nfrom torchvision import datasets, transforms\nfrom collections import defaultdict\n\n# === Config ===\ntrain_dir = '/kaggle/working/processed_dataset/train'\ntest_dir = '/kaggle/working/processed_dataset/test'\nWAVELET = 'db1'\nLEVEL = 2\nPCA_VARIANCE = 0.99  # Keep 99% variance\nTOP_K_PATCHES = 128\nFEATURE_SAVE_PATH = '/kaggle/working/features_wavelet.npy'\nLABEL_SAVE_PATH = '/kaggle/working/true_labels_wavelet.npy'\n\n# === Transforms for ImageFolder (grayscale conversion) ===\ntransform = transforms.Compose([\n    transforms.Resize((64, 64)),  # Match patch size from preprocessing\n    transforms.ToTensor(),\n    transforms.Lambda(lambda x: x.mean(dim=0, keepdim=True))  # Convert to grayscale\n])\n\n# === Load dataset using ImageFolder and group patches by base image ===\ndef load_dataset_image_level(data_dir):\n    dataset = datasets.ImageFolder(root=data_dir, transform=transform)\n    # Group patches by base image name\n    image_dict = defaultdict(list)\n    labels_dict = {}\n    for img_path, label in dataset.imgs:\n        base_img = '_'.join(os.path.basename(img_path).split('_patch_')[0:-1])\n        image_dict[base_img].append((img_path, label, dataset[dataset.imgs.index((img_path, label))][0]))\n        labels_dict[base_img] = label\n    return image_dict, labels_dict\n\n# === Extract wavelet features from one image ===\ndef extract_wavelet_features(image, wavelet=WAVELET, level=LEVEL):\n    # Image is already a grayscale tensor from transform (1, H, W)\n    image = image.squeeze().numpy() * 255.0  # Denormalize to 0-255\n    image = image.astype(np.uint8)\n    coeffs = pywt.wavedec2(image, wavelet=wavelet, level=level)\n    features = []\n    for coeff_level in coeffs:\n        if isinstance(coeff_level, tuple):\n            for arr in coeff_level:\n                features.extend(arr.flatten())\n        else:\n            features.extend(coeff_level.flatten())\n    return np.array(features)\n\n# === Extract features for all images, aggregating patches ===\ndef extract_features(image_dict):\n    X = []\n    y = []\n    filenames = []\n    for base_img, patches in image_dict.items():\n        patch_features = []\n        for _, _, img_tensor in patches:  # Use pre-transformed image tensor\n            features = extract_wavelet_features(img_tensor)\n            patch_features.append(features)\n        \n        if patch_features:\n            # Aggregate patch features (mean pooling)\n            aggregated = np.mean(patch_features, axis=0)\n            X.append(aggregated)\n            y.append(labels_dict[base_img])\n            filenames.append(base_img)\n        else:\n            print(f\"Warning: No valid patches for {base_img}\")\n    \n    return np.array(X), np.array(y), filenames\n\n# === Load and extract features ===\nprint(\"Loading train dataset...\")\ntrain_image_dict, labels_dict = load_dataset_image_level(train_dir)\nprint(\"Extracting train features...\")\nX_train, y_train, _ = extract_features(train_image_dict)\n\nprint(\"Loading test dataset...\")\ntest_image_dict, labels_dict = load_dataset_image_level(test_dir)\nprint(\"Extracting test features...\")\nX_test, y_test, test_fnames = extract_features(test_image_dict)\n\n# === Normalize and apply PCA ===\nscaler = StandardScaler()\nX_train_scaled = scaler.fit_transform(X_train)\nX_test_scaled = scaler.transform(X_test)\n\nprint(\"Applying PCA...\")\npca = PCA(n_components=PCA_VARIANCE, svd_solver='full')\nX_train_pca = pca.fit_transform(X_train_scaled)\nX_test_pca = pca.transform(X_test_scaled)\n\n# === Save feature matrices ===\nnp.save(FEATURE_SAVE_PATH, X_test_pca)\nnp.save(LABEL_SAVE_PATH, y_test)\nprint(f\"Saved test features to {FEATURE_SAVE_PATH}\")\nprint(f\"Saved test labels to {LABEL_SAVE_PATH}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-11T18:59:03.725947Z","iopub.execute_input":"2025-06-11T18:59:03.726591Z","iopub.status.idle":"2025-06-11T19:23:14.700939Z","shell.execute_reply.started":"2025-06-11T18:59:03.726563Z","shell.execute_reply":"2025-06-11T19:23:14.700199Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\n# Load DenseNet121 feature matrix\ntry:\n    densenet_features = np.load('/kaggle/working/features_densenet121.npy')\n    print(\"DenseNet121 features shape:\", densenet_features.shape)\nexcept FileNotFoundError:\n    print(\"Error: DenseNet121 features file not found at /kaggle/working/features_densenet121.npy\")\nexcept Exception as e:\n    print(f\"Error loading DenseNet121 features: {e}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-11T19:56:15.012162Z","iopub.execute_input":"2025-06-11T19:56:15.012447Z","iopub.status.idle":"2025-06-11T19:56:16.353490Z","shell.execute_reply.started":"2025-06-11T19:56:15.012424Z","shell.execute_reply":"2025-06-11T19:56:16.352836Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\n# Load ResNet50 feature matrix\ntry:\n    resnet_features = np.load('/kaggle/input/features-rn50new-npy/features_rn50.npy')\n    print(\"ResNet50 features shape:\", resnet_features.shape)\nexcept FileNotFoundError:\n    print(\"Error: ResNet50 features file not found at /kaggle/input/features-rn50new-npy/features_rn50.npy\")\nexcept Exception as e:\n    print(f\"Error loading ResNet50 features: {e}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-11T20:16:49.043185Z","iopub.execute_input":"2025-06-11T20:16:49.043999Z","iopub.status.idle":"2025-06-11T20:16:54.781083Z","shell.execute_reply.started":"2025-06-11T20:16:49.043967Z","shell.execute_reply":"2025-06-11T20:16:54.780401Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\n# Load wavelet feature matrix\ntry:\n    wavelet_features = np.load('/kaggle/working/features_wavelet.npy')\n    print(\"Wavelet features shape:\", wavelet_features.shape)\nexcept FileNotFoundError:\n    print(\"Error: Wavelet features file not found at /kaggle/working/features_wavelet.npy\")\nexcept Exception as e:\n    print(f\"Error loading wavelet features: {e}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-11T19:57:57.671214Z","iopub.execute_input":"2025-06-11T19:57:57.671562Z","iopub.status.idle":"2025-06-11T19:57:57.681064Z","shell.execute_reply.started":"2025-06-11T19:57:57.671529Z","shell.execute_reply":"2025-06-11T19:57:57.680436Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\n# Load feature matrices\nwavelet_features = np.load('/kaggle/working/features_wavelet.npy')                # (550, 1325)\nresnet50_features = np.load('/kaggle/input/features-rn50new-npy/features_rn50.npy')  # (70400, 2048)\ndensenet121_features = np.load('/kaggle/working/features_densenet121.npy')        # (70400, 1024)\n\n# Confirm expected shapes\nprint(\"Wavelet features shape:\", wavelet_features.shape)\nprint(\"ResNet50 features shape:\", resnet50_features.shape)\nprint(\"DenseNet121 features shape:\", densenet121_features.shape)\n\n# === Aggregating patch-level deep features to image-level ===\n\nnum_images = wavelet_features.shape[0]   # 550 images\npatches_per_image = resnet50_features.shape[0] // num_images  # 70400 / 550 = 127\n\n# Reshape and average over patches\nresnet50_features_image = resnet50_features.reshape(num_images, patches_per_image, -1).mean(axis=1)  # (550, 2048)\ndensenet121_features_image = densenet121_features.reshape(num_images, patches_per_image, -1).mean(axis=1)  # (550, 1024)\n\nprint(\"ResNet50 image-level:\", resnet50_features_image.shape)\nprint(\"DenseNet121 image-level:\", densenet121_features_image.shape)\n\n# === Concatenate all features ===\nconcatenated_features = np.concatenate(\n    [wavelet_features, resnet50_features_image, densenet121_features_image], axis=1\n)\nprint(\"Concatenated features shape:\", concatenated_features.shape)\n\n# Save final features\nnp.save('/kaggle/working/features_concatenated.npy', concatenated_features)\nprint(\"✅ Saved to /kaggle/working/features_concatenated.npy\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-11T20:23:28.101739Z","iopub.execute_input":"2025-06-11T20:23:28.102061Z","iopub.status.idle":"2025-06-11T20:23:28.848020Z","shell.execute_reply.started":"2025-06-11T20:23:28.102039Z","shell.execute_reply":"2025-06-11T20:23:28.847245Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom sklearn.svm import SVC\nfrom sklearn.neighbors import KNeighborsClassifier\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.metrics import accuracy_score\nfrom scipy.stats import mode\n\n# Load fused features and patch-level labels\nfused_features = np.load('/kaggle/working/features_concatenated.npy')              # (550, ?)\ntrue_labels_patch = np.load('/kaggle/working/true_labels_rn50.npy')                # (70585,)\n\n# Convert patch-level labels to image-level\npatches_per_image = 127\ntrue_labels_image = true_labels_patch[::patches_per_image]  # Expected (555,)\ntrue_labels_image = true_labels_image[:fused_features.shape[0]]  # Truncate to (550,)\n\n# Scale features\nscaler = StandardScaler()\nfused_features = scaler.fit_transform(fused_features)\n\n# Initialize classifiers\nsvm = SVC(kernel='rbf', probability=True, random_state=42)\nknn = KNeighborsClassifier(n_neighbors=5)\nrf = RandomForestClassifier(n_estimators=100, random_state=42)\n\n# Train and predict\nsvm_preds = svm.fit(fused_features, true_labels_image).predict(fused_features)\nknn_preds = knn.fit(fused_features, true_labels_image).predict(fused_features)\nrf_preds = rf.fit(fused_features, true_labels_image).predict(fused_features)\n\n# Accuracy scores\nsvm_acc = accuracy_score(true_labels_image, svm_preds) * 100\nknn_acc = accuracy_score(true_labels_image, knn_preds) * 100\nrf_acc = accuracy_score(true_labels_image, rf_preds) * 100\n\n# Print individual classifier accuracy\nprint(f\"✅ SVM Accuracy: {svm_acc:.2f}%\")\nprint(f\"✅ KNN Accuracy: {knn_acc:.2f}%\")\nprint(f\"✅ Random Forest Accuracy: {rf_acc:.2f}%\")\n\n# Save individual predictions\ndf = pd.DataFrame({\n    'SVM': svm_preds,\n    'KNN': knn_preds,\n    'RF': rf_preds,\n    'True_Label': true_labels_image\n})\ndf.to_csv('/kaggle/working/classifier_outputs.csv', index=False)\nprint(\"📁 Saved classifier predictions to /kaggle/working/classifier_outputs.csv\")\n\n# === Majority Voting Ensemble ===\nvotes = df[['SVM', 'KNN', 'RF']].values\nmajority_preds, _ = mode(votes, axis=1, keepdims=True)\nmajority_preds = majority_preds.flatten()\n\n# Ensemble accuracy\nensemble_acc = accuracy_score(true_labels_image, majority_preds) * 100\nprint(f\"🏁 Ensemble (majority voting) Accuracy: {ensemble_acc:.2f}%\")\n\n# Save ensemble predictions\ndf['Ensemble'] = majority_preds\ndf.to_csv('/kaggle/working/resDenseWave_result.csv', index=False)\nprint(\"📁 Saved ensemble results to /kaggle/working/resDenseWave_result.csv\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-11T20:45:40.959256Z","iopub.execute_input":"2025-06-11T20:45:40.960172Z","iopub.status.idle":"2025-06-11T20:45:45.775102Z","shell.execute_reply.started":"2025-06-11T20:45:40.960131Z","shell.execute_reply":"2025-06-11T20:45:45.774380Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom sklearn.metrics import confusion_matrix\n\n# Load ensemble results\ndf = pd.read_csv('/kaggle/working/resDenseWave_result.csv')\n\n# True and predicted labels\ny_true = df['True_Label']\ny_pred = df['Ensemble']\n\n# Compute normalized confusion matrix (percentage per true class)\ncm = confusion_matrix(y_true, y_pred, normalize='true') * 100  # Row-wise normalization\n\n# Plot\nplt.figure(figsize=(8,6))\nsns.heatmap(cm, annot=True, fmt='.2f', cmap='Blues', cbar=True)\nplt.title('Confusion Matrix  fusion model(ResNet50 + Handcrafted + DenseNet121)')\nplt.xlabel('Predicted Label')\nplt.ylabel('True Label')\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T06:03:01.950892Z","iopub.execute_input":"2025-06-12T06:03:01.951199Z","iopub.status.idle":"2025-06-12T06:03:02.331553Z","shell.execute_reply.started":"2025-06-12T06:03:01.951178Z","shell.execute_reply":"2025-06-12T06:03:02.330820Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import accuracy_score\n\n# Load predictions\ndf = pd.read_csv('/kaggle/working/resDenseWave_result.csv')\n\n# True labels\ny_true = df['True_Label']\n\n# Classifiers to compare\nmodels = ['SVM', 'KNN', 'RF', 'Ensemble']\naccuracies = []\n\n# Compute accuracy for each model\nfor model in models:\n    acc = accuracy_score(y_true, df[model]) * 100\n    accuracies.append(acc)\n\n# Plot\nplt.figure(figsize=(8, 5))\nbars = plt.bar(models, accuracies, color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'])\nplt.title('Classifier Accuracy Comparison')\nplt.ylabel('Accuracy (%)')\nplt.ylim(0, 105)\nplt.grid(axis='y', linestyle='--', alpha=0.5)\n\n# Annotate accuracy values on top\nfor bar in bars:\n    height = bar.get_height()\n    plt.text(bar.get_x() + bar.get_width() / 2, height + 1, f'{height:.2f}%', \n             ha='center', va='bottom', fontsize=10)\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T05:32:30.691291Z","iopub.execute_input":"2025-06-12T05:32:30.691673Z","iopub.status.idle":"2025-06-12T05:32:30.838759Z","shell.execute_reply.started":"2025-06-12T05:32:30.691652Z","shell.execute_reply":"2025-06-12T05:32:30.838049Z"}},"outputs":[],"execution_count":null}]}