{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":23812,"sourceType":"datasetVersion","datasetId":17810},{"sourceId":1166777,"sourceType":"datasetVersion","datasetId":661308}],"dockerImageVersionId":30761,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\n\n# List directories and files\ndataset_path = '/kaggle/input'\nos.listdir(dataset_path)\n","metadata":{"execution":{"iopub.status.busy":"2025-04-04T10:05:55.251899Z","iopub.execute_input":"2025-04-04T10:05:55.252797Z","iopub.status.idle":"2025-04-04T10:05:55.258653Z","shell.execute_reply.started":"2025-04-04T10:05:55.252762Z","shell.execute_reply":"2025-04-04T10:05:55.257795Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\n\n# Check if a GPU is available\nprint(torch.cuda.is_available()) \n\n# Print the name of the GPU\nprint(torch.cuda.get_device_name(0))\n","metadata":{"execution":{"iopub.status.busy":"2025-04-04T10:05:59.647026Z","iopub.execute_input":"2025-04-04T10:05:59.647997Z","iopub.status.idle":"2025-04-04T10:05:59.653181Z","shell.execute_reply.started":"2025-04-04T10:05:59.647949Z","shell.execute_reply":"2025-04-04T10:05:59.652152Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import datasets, models, transforms\nfrom torch.utils.data import DataLoader\nfrom torchvision.models import vgg16, vgg19\nfrom torchvision.transforms import functional as F\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport os\nimport torch.nn.functional as F\n\n\nfrom torch.nn import TransformerEncoder, TransformerEncoderLayer\n\n# from pytorch_grad_cam import GradCAM\n# from pytorch_grad_cam.utils.image import show_cam_on_image\n# from pytorch_grad_cam.utils.model_targets import ClassifierOutputTarget","metadata":{"execution":{"iopub.status.busy":"2025-04-04T10:06:04.287838Z","iopub.execute_input":"2025-04-04T10:06:04.288197Z","iopub.status.idle":"2025-04-04T10:06:04.294054Z","shell.execute_reply.started":"2025-04-04T10:06:04.288167Z","shell.execute_reply":"2025-04-04T10:06:04.293044Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint(device)","metadata":{"execution":{"iopub.status.busy":"2025-04-04T10:06:08.823140Z","iopub.execute_input":"2025-04-04T10:06:08.823823Z","iopub.status.idle":"2025-04-04T10:06:08.828450Z","shell.execute_reply.started":"2025-04-04T10:06:08.823790Z","shell.execute_reply":"2025-04-04T10:06:08.827533Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class HybridLoss(nn.Module):\n    def __init__(self, alpha, gamma, smooth=1.0):\n        super(HybridLoss, self).__init__()\n        self.alpha = alpha\n        self.gamma = gamma\n        self.smooth = smooth\n\n    def focal_loss(self, outputs, labels):\n        # Apply softmax to get probabilities\n        probs = F.softmax(outputs, dim=1)\n\n        # Compute cross-entropy loss per example\n        ce_loss = F.cross_entropy(outputs, labels, reduction='none')\n\n        # Get probabilities for the correct class labels\n        probs = probs.gather(1, labels.unsqueeze(1)).squeeze(1)\n\n        # Compute focal loss\n        focal_loss = self.alpha * ((1 - probs) ** self.gamma) * ce_loss\n        focal_loss = focal_loss.mean()\n\n        return focal_loss\n\n    def dice_loss(self, outputs, labels):\n        # Convert labels to one-hot encoding\n        labels_one_hot = torch.eye(outputs.size(1)).to(device=outputs.device)[labels]\n\n        # Apply softmax to get probabilities\n        probs = F.softmax(outputs, dim=1)\n\n        # Dice Loss calculation\n        intersection = torch.sum(probs * labels_one_hot, dim=0)\n        dice_loss = 1 - (2 * intersection + self.smooth) / (\n            torch.sum(probs, dim=0) + torch.sum(labels_one_hot, dim=0) + self.smooth\n        )\n        dice_loss = torch.mean(dice_loss)  # Average over all classes\n\n        return dice_loss\n\n    def forward(self, outputs, labels):\n        # Compute individual losses\n        ce_loss = F.cross_entropy(outputs, labels)\n        focal = self.focal_loss(outputs, labels)\n        dice = self.dice_loss(outputs, labels)\n\n        # Combine all losses with weights\n        combined_loss = 0.5 * ce_loss + 0.5 * focal + 0* dice\n        return combined_loss\n\n","metadata":{"execution":{"iopub.status.busy":"2025-04-04T10:06:11.792615Z","iopub.execute_input":"2025-04-04T10:06:11.792955Z","iopub.status.idle":"2025-04-04T10:06:11.801223Z","shell.execute_reply.started":"2025-04-04T10:06:11.792926Z","shell.execute_reply":"2025-04-04T10:06:11.800366Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"criterion = HybridLoss(alpha=0.25, gamma=2.0)","metadata":{"execution":{"iopub.status.busy":"2025-04-04T10:06:41.698137Z","iopub.execute_input":"2025-04-04T10:06:41.698856Z","iopub.status.idle":"2025-04-04T10:06:41.702894Z","shell.execute_reply.started":"2025-04-04T10:06:41.698820Z","shell.execute_reply":"2025-04-04T10:06:41.701833Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torchvision.models as models\nfrom transformers import ViTModel, ViTFeatureExtractor\n\n# Load pretrained ViT model\nvit_model = ViTModel.from_pretrained(\"google/vit-base-patch16-224-in21k\")\nvit_feature_extractor = ViTFeatureExtractor.from_pretrained(\"google/vit-base-patch16-224-in21k\")\n\n# Freeze ViT parameters (optional)\nfor param in vit_model.parameters():\n    param.requires_grad = False\n\n# Load pre-trained ResNet50 without the FC layers\nresnet50 = models.resnet50(pretrained=True)\nresnet50 = nn.Sequential(*list(resnet50.children())[:-2])  # Remove avgpool and fc\n\nfor param in resnet50.parameters():\n    param.requires_grad = False\n\n# Final model\nclass EnsembleModel(nn.Module):\n    def __init__(self, resnet50, vit_model, vit_feature_extractor, num_classes):\n        super(EnsembleModel, self).__init__()\n        self.resnet50 = resnet50\n        self.vit_model = vit_model\n        self.vit_feature_extractor = vit_feature_extractor\n        self.num_classes = num_classes\n\n        self.resnet_fc = nn.Sequential(\n            nn.AdaptiveAvgPool2d((1, 1)),\n            nn.Flatten(),\n            nn.Linear(2048, 512),\n            nn.ReLU(),\n        )\n\n        self.dropout = nn.Dropout(p=0.5)\n        self.classifier = nn.Linear(512 + vit_model.config.hidden_size, num_classes)\n\n    def forward(self, x):\n        # ResNet feature path\n        resnet_feat = self.resnet50(x)\n        resnet_feat = self.resnet_fc(resnet_feat)\n\n        # Denormalize image for ViT path\n        mean = torch.tensor([0.485, 0.456, 0.406]).to(x.device).view(1, 3, 1, 1)\n        std = torch.tensor([0.229, 0.224, 0.225]).to(x.device).view(1, 3, 1, 1)\n        x_denorm = x * std + mean\n\n        # Convert batch to list of PIL images\n        from torchvision.transforms.functional import to_pil_image\n        images_pil = [to_pil_image(img.cpu()) for img in x_denorm]\n\n        vit_inputs = self.vit_feature_extractor(images_pil, return_tensors=\"pt\").pixel_values.to(x.device)\n        vit_outputs = self.vit_model(vit_inputs)\n        vit_feat = vit_outputs.pooler_output  # [batch_size, hidden_size]\n\n        # Concatenate ResNet and ViT features\n        combined = torch.cat((resnet_feat, vit_feat), dim=1)\n        output = self.classifier(self.dropout(combined))\n        return output\n\n\n# Initialize the Transformer with the same parameters\n# d_model = 1024  # Transformer input size\n# nhead = 4  # Number of heads in multi-head attention\n# num_layers = 2  # Number of transformer layers\n# transformer = SimpleTransformer(d_model=d_model, nhead=nhead, num_layers=num_layers)\n\n# Initialize the ensemble model\nnum_classes = 2  # Adjust for your task (binary classification in this case)\nensemble_model = EnsembleModel(resnet50,vit_model, vit_feature_extractor, num_classes)\n\n# Move the model to the appropriate device (e.g., GPU if available)\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nensemble_model = ensemble_model.to(device)\n\n\n","metadata":{"execution":{"iopub.status.busy":"2025-04-04T10:12:49.145813Z","iopub.execute_input":"2025-04-04T10:12:49.146619Z","iopub.status.idle":"2025-04-04T10:12:50.610988Z","shell.execute_reply.started":"2025-04-04T10:12:49.146583Z","shell.execute_reply":"2025-04-04T10:12:50.610174Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision.datasets import ImageFolder\nfrom torch.utils.data import DataLoader,Subset\nimport torchvision.transforms as transforms\nfrom sklearn.model_selection import KFold\nfrom torch.utils.data import ConcatDataset\n\n# Image transformations\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.RandomHorizontalFlip(),  # Randomly flip images\n    transforms.RandomRotation(10),  # Randomly rotate images\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),  # Random changes in color\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n])\n\n# # Paths for train, val, and test datasets\ntrain_dataset = ImageFolder('/kaggle/input/pneumonia-xray-images/train', transform=transform)\nval_dataset = ImageFolder('/kaggle/input/pneumonia-xray-images/val', transform=transform)\ntest_dataset = ImageFolder('/kaggle/input/chest-xray-pneumonia/chest_xray/test', transform=transform)\n\n# Data loaders\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=32, shuffle=False)\ntest_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)\n\n# # Print dataset sizes\nprint(f'Train dataset size: {len(train_dataset)}')\nprint(f'Validation dataset size: {len(val_dataset)}')\nprint(f'Test dataset size: {len(test_dataset)}')\n\n# Dataloaders for training and validation\ndataloaders = {\n    'train': train_loader,\n    'val': val_loader\n}\n\ndataset_sizes = {\n    'train': len(train_dataset),\n    'val': len(val_dataset)\n}\n\n","metadata":{"execution":{"iopub.status.busy":"2025-04-04T10:13:00.219775Z","iopub.execute_input":"2025-04-04T10:13:00.220104Z","iopub.status.idle":"2025-04-04T10:13:05.324509Z","shell.execute_reply.started":"2025-04-04T10:13:00.220077Z","shell.execute_reply":"2025-04-04T10:13:05.323613Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import WeightedRandomSampler\nimport copy\n\n\noptimizer = optim.Adam(ensemble_model.classifier.parameters(), lr=0.005,weight_decay=1e-4)\nscheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', patience=2, factor=0.1)\n\ndef train_model(model, criterion, optimizer, scheduler, num_epochs):\n    best_model_wts = copy.deepcopy(model.state_dict())\n    best_acc = 0.0\n\n    for epoch in range(num_epochs):\n        print(f'Epoch {epoch}/{num_epochs - 1}')\n        print('-' * 10)\n\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                model.train()  # Set model to training mode\n            else:\n                model.eval()   # Set model to evaluate mode\n\n            running_loss = 0.0\n            corrects = 0\n\n            for inputs, labels in dataloaders[phase]:\n                inputs, labels = inputs.to(device), labels.to(device)\n\n                optimizer.zero_grad()\n\n                with torch.set_grad_enabled(phase == 'train'):\n                    outputs = model(inputs)\n                    loss = criterion(outputs, labels)\n\n                    if phase == 'train':\n                        loss.backward()\n                        optimizer.step()\n\n                running_loss += loss.item() * inputs.size(0)\n                _, preds = torch.max(outputs, 1)\n                corrects += torch.sum(preds == labels.data)\n\n            epoch_loss = running_loss / dataset_sizes[phase]\n            epoch_acc = corrects.double() / dataset_sizes[phase]\n\n            print(f'{phase} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')\n\n            # Step the scheduler only on validation loss\n            if phase == 'val':\n                scheduler.step(epoch_loss)\n\n    return model\n\n","metadata":{"execution":{"iopub.status.busy":"2025-04-04T10:14:53.669385Z","iopub.execute_input":"2025-04-04T10:14:53.670136Z","iopub.status.idle":"2025-04-04T10:14:53.679270Z","shell.execute_reply.started":"2025-04-04T10:14:53.670105Z","shell.execute_reply":"2025-04-04T10:14:53.678315Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nensemble_model = train_model(ensemble_model, criterion, optimizer, scheduler, num_epochs=50)","metadata":{"execution":{"iopub.status.busy":"2025-04-04T10:15:00.346909Z","iopub.execute_input":"2025-04-04T10:15:00.347253Z","iopub.status.idle":"2025-04-04T10:33:52.790144Z","shell.execute_reply.started":"2025-04-04T10:15:00.347221Z","shell.execute_reply":"2025-04-04T10:33:52.788741Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import precision_score, recall_score, f1_score\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\ntorch.save(ensemble_model.state_dict(), 'pneumonia_detection_model.pth')","metadata":{"execution":{"iopub.status.busy":"2024-09-21T12:42:47.527002Z","iopub.execute_input":"2024-09-21T12:42:47.527769Z","iopub.status.idle":"2024-09-21T12:42:49.124675Z","shell.execute_reply.started":"2024-09-21T12:42:47.527726Z","shell.execute_reply":"2024-09-21T12:42:49.123613Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from collections import Counter\n\ntrain_labels = [label for _, label in train_dataset]  # Assuming you have a labeled dataset\nval_labels = [label for _, label in val_dataset]\n\ntrain_counter = Counter(train_labels)\nval_counter = Counter(val_labels)\n\nprint(\"Training set class distribution:\", train_counter)\nprint(\"Validation set class distribution:\", val_counter)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-20T20:19:21.049949Z","iopub.execute_input":"2024-09-20T20:19:21.050637Z","iopub.status.idle":"2024-09-20T20:20:43.198516Z","shell.execute_reply.started":"2024-09-20T20:19:21.050597Z","shell.execute_reply":"2024-09-20T20:20:43.197441Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def test_model(model, criterion, test_loader):\n    model.eval()  # Set the model to evaluation mode\n    running_loss = 0.0\n    corrects = 0\n    total_samples = 0\n\n    all_preds = []\n    all_labels = []\n\n    with torch.no_grad():  # Disable gradient computation\n        for inputs, labels in test_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n\n            running_loss += loss.item() * inputs.size(0)\n            _, preds = torch.max(outputs, 1)\n            corrects += torch.sum(preds == labels.data)\n            total_samples += labels.size(0)\n\n            all_preds.extend(preds.cpu().numpy())\n            all_labels.extend(labels.cpu().numpy())\n\n    test_loss = running_loss / total_samples\n    test_acc = corrects.double() / total_samples\n\n    precision = precision_score(all_labels, all_preds)\n    recall = recall_score(all_labels, all_preds)\n    f1 = f1_score(all_labels, all_preds)\n\n    print(f'Test Loss: {test_loss:.4f} Acc: {test_acc:.4f}')\n    print(f'Precision: {precision:.4f} | Recall: {recall:.4f} | F1-score: {f1:.4f}')\n    return test_loss, test_acc\n\n# Call the test function\ntest_model(ensemble_model, criterion, test_loader)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-21T21:59:54.125242Z","iopub.execute_input":"2024-09-21T21:59:54.126163Z","iopub.status.idle":"2024-09-21T22:00:11.623600Z","shell.execute_reply.started":"2024-09-21T21:59:54.126121Z","shell.execute_reply":"2024-09-21T22:00:11.622645Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install captum","metadata":{"execution":{"iopub.status.busy":"2024-09-21T12:51:48.467094Z","iopub.execute_input":"2024-09-21T12:51:48.468013Z","iopub.status.idle":"2024-09-21T12:52:03.672965Z","shell.execute_reply.started":"2024-09-21T12:51:48.467956Z","shell.execute_reply":"2024-09-21T12:52:03.671600Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nfrom captum.attr import IntegratedGradients\n\ndef explain_model_cuda(model, input_tensor, target_class, device=\"cuda\" if torch.cuda.is_available() else \"cpu\"):\n    \n    # Move model and input to the specified device\n    model.to(device)\n    input_tensor = input_tensor.to(device)\n\n    # Ensure model is in evaluation mode\n    model.eval()\n\n    # Set requires_grad for input\n    input_tensor.requires_grad = True\n\n    # Create IntegratedGradients instance on the same device\n    ig = IntegratedGradients(model)\n\n    # Calculate attributions with a reasonable number of steps (adjust as needed)\n    attribution = ig.attribute(input_tensor, target=target_class, n_steps=50)\n\n    # Detach from computation graph (if desired)\n    attribution = attribution.detach()\n\n    return attribution\n\n# Example usage with test data loader\ninputs, targets = next(iter(test_loader))\ninput_tensor = inputs[0:1].to(\"cuda\")  # Assuming test_loader returns data on CPU\ntarget_class = targets[0].item()\n\n# Explain the prediction on GPU (if available)\nattribution = explain_model_cuda(ensemble_model, input_tensor, target_class)\n\n# Visualization (optional, requires matplotlib)\nimport matplotlib.pyplot as plt\nif attribution.is_cuda:  # Check if attribution is on GPU\n    attr = attribution.cpu().detach().numpy().squeeze()  # Transfer to CPU\nelse:\n    attr = attribution.detach().numpy().squeeze()  # No transfer needed\nplt.imshow(attr[0], cmap='hot')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-09-21T12:53:49.125964Z","iopub.execute_input":"2024-09-21T12:53:49.126674Z","iopub.status.idle":"2024-09-21T12:53:51.350939Z","shell.execute_reply.started":"2024-09-21T12:53:49.126635Z","shell.execute_reply":"2024-09-21T12:53:51.349986Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom torchvision import transforms\nfrom PIL import Image\n\n# Load your test image\nimage_path = '/kaggle/input/chest-xray-pneumonia/chest_xray/val/PNEUMONIA/person1949_bacteria_4880.jpeg'\nimage = Image.open(image_path).convert('RGB')\n\n# Define your transformations (make sure they match those used during training)\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.RandomHorizontalFlip(),  # Randomly flip images\n    transforms.RandomRotation(10),  # Randomly rotate images\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),  # Random changes in color\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n])\n\n# Apply transformations\ninput_image = transform(image).unsqueeze(0)  # Add batch dimension\n\n# Make sure to use the right device (CPU or GPU)\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nensemble_model.eval()  # Set the model to evaluation mode\ninput_image = input_image.to(device)\n\n# Get the output from the model\nwith torch.no_grad():  # No need to track gradients\n    output = ensemble_model(input_image)\n\n# If using a softmax layer, apply it to get probabilities\nprobabilities = torch.softmax(output, dim=1)\n\n# Get the predicted class\npredicted_class = torch.argmax(probabilities, dim=1)\n\nprint(f\"Predicted class: {predicted_class.item()}\")\nprint(f\"Probabilities: {probabilities}\")\n","metadata":{"execution":{"iopub.status.busy":"2024-09-21T22:03:21.282957Z","iopub.execute_input":"2024-09-21T22:03:21.283345Z","iopub.status.idle":"2024-09-21T22:03:21.331010Z","shell.execute_reply.started":"2024-09-21T22:03:21.283307Z","shell.execute_reply":"2024-09-21T22:03:21.330086Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null}]}