{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":39272,"databundleVersionId":4629629,"sourceType":"competition"},{"sourceId":4619402,"sourceType":"datasetVersion","datasetId":2688773},{"sourceId":89895,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":75387,"modelId":100113}],"dockerImageVersionId":30747,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nfrom sklearn.model_selection import train_test_split\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import models, transforms\nfrom torch.utils.data import Dataset, DataLoader\nfrom PIL import Image\nimport os\nimport time\nfrom tqdm import tqdm\nfrom datetime import timedelta\nimport matplotlib.pyplot as plt\nimport torchvision\nimport torch.nn.functional as F\n\n# Path to the CSV file\ncsv_file = '/kaggle/input/rsna-breast-cancer-detection/train.csv'\nimage_directory = '/kaggle/input/rsna-breast-cancer-256-pngs'\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv(csv_file)\n\n# Columns to keep for density classification\ncolumns_to_keep = ['patient_id', 'image_id', 'density', 'age', 'laterality', 'view', 'BIRADS', 'difficult_negative_case', 'implant']\n\n# Create a new DataFrame with only the selected columns\ndf_selected = df[columns_to_keep]\n\n# Discard rows where the 'density' column has NaN values\ndf_selected_cleaned = df_selected.dropna(subset=['density'])\n\n# Discard rows where the 'implant' column is set to 1\ndf_selected_cleaned = df_selected_cleaned[df_selected_cleaned['implant'] != 1]\n","metadata":{"execution":{"iopub.status.busy":"2024-08-06T08:42:37.859802Z","iopub.execute_input":"2024-08-06T08:42:37.860155Z","iopub.status.idle":"2024-08-06T08:42:37.949937Z","shell.execute_reply.started":"2024-08-06T08:42:37.860126Z","shell.execute_reply":"2024-08-06T08:42:37.949004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Encode the density labels\nfrom sklearn.preprocessing import LabelEncoder\n\nlabel_encoder = LabelEncoder()\ndf_selected_cleaned['density'] = label_encoder.fit_transform(df_selected_cleaned['density'])\n","metadata":{"execution":{"iopub.status.busy":"2024-08-06T08:42:46.743646Z","iopub.execute_input":"2024-08-06T08:42:46.744096Z","iopub.status.idle":"2024-08-06T08:42:46.757395Z","shell.execute_reply.started":"2024-08-06T08:42:46.744057Z","shell.execute_reply":"2024-08-06T08:42:46.756346Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Split the unique patients into train, validation, and test sets\ntrain_patients, test_patients = train_test_split(unique_patients, test_size=0.2, stratify=unique_patients['density'], random_state=42)\ntrain_patients, val_patients = train_test_split(train_patients, test_size=0.25, stratify=train_patients['density'], random_state=42)  # 0.25 * 0.8 = 0.2\n\n# Function to get all images for a set of patients\ndef get_images_for_patients(patients, df):\n    return df[df['patient_id'].isin(patients['patient_id'])]\n\n# Get all images for the train, validation, and test sets\ntrain_df = get_images_for_patients(train_patients, df_selected_cleaned)\nval_df = get_images_for_patients(val_patients, df_selected_cleaned)\ntest_df = get_images_for_patients(test_patients, df_selected_cleaned)\n\n# Save the splits to CSV files\ntrain_df[['patient_id', 'image_id','density']].to_csv('/kaggle/working/train_set-v2.csv', index=False)\nval_df[['patient_id', 'image_id','density']].to_csv('/kaggle/working/val_set-v2.csv', index=False)\ntest_df[['patient_id', 'image_id','density']].to_csv('/kaggle/working/test_set-v2.csv', index=False)\n\n# Display the first few rows of each split\nprint(\"Training Set:\")\nprint(train_df.head())\n\nprint(\"Validation Set:\")\nprint(val_df.head())\n\nprint(\"Test Set:\")\nprint(test_df.head())","metadata":{"execution":{"iopub.status.busy":"2024-08-06T08:45:50.406225Z","iopub.execute_input":"2024-08-06T08:45:50.406872Z","iopub.status.idle":"2024-08-06T08:45:50.498031Z","shell.execute_reply.started":"2024-08-06T08:45:50.406838Z","shell.execute_reply":"2024-08-06T08:45:50.497096Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Display class distribution in each split\nprint(\"Class distribution in Training set:\")\nprint(train_df['density'].value_counts())\n\nprint(\"Class distribution in Validation set:\")\nprint(val_df['density'].value_counts())\n\nprint(\"Class distribution in Test set:\")\nprint(test_df['density'].value_counts())","metadata":{"execution":{"iopub.status.busy":"2024-08-06T08:44:15.800913Z","iopub.execute_input":"2024-08-06T08:44:15.801256Z","iopub.status.idle":"2024-08-06T08:44:15.81035Z","shell.execute_reply.started":"2024-08-06T08:44:15.801228Z","shell.execute_reply":"2024-08-06T08:44:15.809445Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check for duplications in patient_id across the datasets\ntrain_patients = set(train_df['patient_id'])\nval_patients = set(val_df['patient_id'])\ntest_patients = set(test_df['patient_id'])\n\n# Find any duplications\ndup_in_train_val = train_patients.intersection(val_patients)\ndup_in_train_test = train_patients.intersection(test_patients)\ndup_in_val_test = val_patients.intersection(test_patients)\n\n# Display results\nif not dup_in_train_val and not dup_in_train_test and not dup_in_val_test:\n    print(\"No duplications found across the train, validation, and test sets.\")\nelse:\n    if dup_in_train_val:\n        print(f\"Duplications found between train and validation sets: {dup_in_train_val}\")\n    if dup_in_train_test:\n        print(f\"Duplications found between train and test sets: {dup_in_train_test}\")\n    if dup_in_val_test:\n        print(f\"Duplications found between validation and test sets: {dup_in_val_test}\")\n\n","metadata":{"execution":{"iopub.status.busy":"2024-08-06T08:44:26.065393Z","iopub.execute_input":"2024-08-06T08:44:26.06607Z","iopub.status.idle":"2024-08-06T08:44:26.078738Z","shell.execute_reply.started":"2024-08-06T08:44:26.06604Z","shell.execute_reply":"2024-08-06T08:44:26.077756Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the transformations for training\ntrain_transform = transforms.Compose([\n    transforms.Resize((256, 256)),\n    transforms.RandomRotation(30),\n    transforms.RandomAffine(\n        degrees=0,\n        translate=(0.2, 0.2),\n        shear=0.2,\n        scale=(0.8, 1.2)\n    ),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\nval_test_transform = transforms.Compose([\n    transforms.Resize((256, 256)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n# Define the custom dataset\nclass BreastCancerDataset(Dataset):\n    def __init__(self, dataframe, image_dir, transform=None):\n        self.dataframe = dataframe\n        self.image_dir = image_dir\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.dataframe)\n\n    def __getitem__(self, idx):\n        row = self.dataframe.iloc[idx]\n        patient_id = int(row['patient_id'])\n        image_id = int(row['image_id'])\n        img_name = os.path.join(self.image_dir, f\"{patient_id}_{image_id}.png\")\n        image = Image.open(img_name).convert('RGB')\n        \n        label = row['density']\n        \n        if self.transform:\n            image = self.transform(image)\n\n        return image, label\n\n# Create the datasets\ntrain_dataset = BreastCancerDataset(train_df, image_directory, transform=train_transform)\nval_dataset = BreastCancerDataset(val_df, image_directory, transform=val_test_transform)\ntest_dataset = BreastCancerDataset(test_df, image_directory, transform=val_test_transform)\n\n# Create the 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","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Function to visualize a batch of images\ndef imshow(img, title=None):\n    npimg = img.numpy().transpose((1, 2, 0))\n    plt.imshow(npimg)\n    if title is not None:\n        plt.title(title)\n    plt.show()\n\n# Function to visualize a batch of images from a DataLoader\ndef visualize_batch(dataloader, title, num_images=8):\n    # Get a batch of data\n    images, labels = next(iter(dataloader))\n    \n    # Select only the first num_images\n    images = images[:num_images]\n    labels = labels[:num_images]\n    \n    # Make a grid from batch with padding\n    out = torchvision.utils.make_grid(images, nrow=num_images, padding=2)\n    imshow(out, title=title)\n\n# Visualize a batch from the training DataLoader\nprint(\"Training DataLoader\")\nvisualize_batch(train_loader, \"Training Data\")\n\n# Visualize a batch from the validation DataLoader\nprint(\"Validation DataLoader\")\nvisualize_batch(val_loader, \"Validation Data\")\n\n# Visualize a batch from the test DataLoader\nprint(\"Test DataLoader\")\nvisualize_batch(test_loader, \"Test Data\")\n","metadata":{"execution":{"iopub.status.busy":"2024-08-06T06:41:27.806458Z","iopub.execute_input":"2024-08-06T06:41:27.806755Z","iopub.status.idle":"2024-08-06T06:41:28.976752Z","shell.execute_reply.started":"2024-08-06T06:41:27.806729Z","shell.execute_reply":"2024-08-06T06:41:28.97589Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check a batch of data from the train loader\nfor images, labels in train_loader:\n    print(f\"Train Loader - Images shape: {images.shape}\")\n    print(f\"Train Loader - Labels shape: {labels.shape}\")\n    break  # Only need to check one batch\n    \n# Check a batch of data from the train loader\nfor images, labels in val_loader:\n    print(f\"Val Loader - Images shape: {images.shape}\")\n    print(f\"Val Loader - Labels shape: {labels.shape}\")\n    break  # Only need to check one batch","metadata":{"execution":{"iopub.status.busy":"2024-08-06T06:41:28.977973Z","iopub.execute_input":"2024-08-06T06:41:28.978315Z","iopub.status.idle":"2024-08-06T06:41:29.276762Z","shell.execute_reply.started":"2024-08-06T06:41:28.978282Z","shell.execute_reply":"2024-08-06T06:41:29.275788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport os\nimport torch.nn as nn\nimport torchvision.models as models\n\n# Define the model class\nclass CustomDenseNet121(nn.Module):\n    def __init__(self, num_classes=4):\n        super(CustomDenseNet121, self).__init__()\n        self.densenet = models.densenet121(pretrained=True)\n        self.densenet.classifier = nn.Linear(self.densenet.classifier.in_features, num_classes)\n        \n    def forward(self, x):\n        x = self.densenet(x)\n        return x\n\n# Initialize the model\nnum_classes = 4  # Adjust based on your dataset\nmodel = CustomDenseNet121(num_classes=num_classes)\n\n# Save the model to a temporary file\ntemp_file = 'temp_model.pth'\ntorch.save(model.state_dict(), temp_file)\n\n# Check the size of the model\nmodel_size_mb = os.path.getsize(temp_file) / (1024 * 1024)\nprint(f'Model size: {model_size_mb:.2f} MB')\n\n# Clean up the temporary file\nos.remove(temp_file)\n\n# Count the number of parameters in the model\ntotal_params = sum(p.numel() for p in model.parameters())\ntrainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)\nnon_trainable_params = total_params - trainable_params\n\nprint(f\"Total parameters: {total_params}\")\nprint(f\"Trainable parameters: {trainable_params}\")\nprint(f\"Non-trainable parameters: {non_trainable_params}\")\n","metadata":{"execution":{"iopub.status.busy":"2024-08-06T08:25:28.62316Z","iopub.execute_input":"2024-08-06T08:25:28.62352Z","iopub.status.idle":"2024-08-06T08:25:28.941593Z","shell.execute_reply.started":"2024-08-06T08:25:28.623492Z","shell.execute_reply":"2024-08-06T08:25:28.940707Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Wrap the model with DataParallel for multi-GPU training\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = nn.DataParallel(model)\nmodel = model.to(device)","metadata":{"execution":{"iopub.status.busy":"2024-08-06T06:41:29.523633Z","iopub.execute_input":"2024-08-06T06:41:29.523921Z","iopub.status.idle":"2024-08-06T06:41:29.559993Z","shell.execute_reply.started":"2024-08-06T06:41:29.523898Z","shell.execute_reply":"2024-08-06T06:41:29.558982Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define loss function and optimizer\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001)\n\n# Early Stopping\nclass EarlyStopping:\n    def __init__(self, patience=10, min_delta=0):\n        self.patience = patience\n        self.min_delta = min_delta\n        self.counter = 0\n        self.best_loss = None\n        self.early_stop = False\n\n    def check_early_stop(self, val_loss):\n        if self.best_loss is None:\n            self.best_loss = val_loss\n        elif val_loss > self.best_loss - self.min_delta:\n            self.counter += 1\n            if self.counter >= self.patience:\n                self.early_stop = True\n        else:\n            self.best_loss = val_loss\n            self.counter = 0\n\n# Reduce Learning Rate on Plateau\nclass ReduceLROnPlateau:\n    def __init__(self, optimizer, factor=0.1, patience=5, min_lr=1e-6):\n        self.optimizer = optimizer\n        self.factor = factor\n        self.patience = patience\n        self.min_lr = min_lr\n        self.counter = 0\n        self.best_loss = None\n\n    def step(self, val_loss):\n        if self.best_loss is None:\n            self.best_loss = val_loss\n        elif val_loss > self.best_loss:\n            self.counter += 1\n            if self.counter >= self.patience:\n                self._reduce_lr()\n                self.counter = 0\n        else:\n            self.best_loss = val_loss\n            self.counter = 0\n\n    def _reduce_lr(self):\n        for param_group in self.optimizer.param_groups:\n            new_lr = max(param_group['lr'] * self.factor, self.min_lr)\n            param_group['lr'] = new_lr\n            print(f'Reduced learning rate to {new_lr}')\n\n# Model Checkpointing\ndef save_checkpoint(model, epoch, val_loss, best_loss, path=\"model_checkpoint.pth\"):\n    if val_loss < best_loss:\n        print(f'Saving model with val_loss {val_loss:.4f} at epoch {epoch+1}')\n        torch.save(model.state_dict(), path)\n        best_loss = val_loss\n    return best_loss\n\n# Initialize early stopping and learning rate scheduler\nearly_stopping = EarlyStopping(patience=10, min_delta=0.001)\nlr_scheduler = ReduceLROnPlateau(optimizer, factor=0.2, patience=5, min_lr=1e-6)\nbest_loss = float('inf')\n","metadata":{"execution":{"iopub.status.busy":"2024-08-06T06:41:36.272653Z","iopub.execute_input":"2024-08-06T06:41:36.273004Z","iopub.status.idle":"2024-08-06T06:41:36.290397Z","shell.execute_reply.started":"2024-08-06T06:41:36.272975Z","shell.execute_reply":"2024-08-06T06:41:36.28943Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Track history\ntrain_losses = []\nval_losses = []\ntrain_accuracies = []\nval_accuracies = []\n\n# Record the start time\nstart_time = time.time()\n\n# Training loop\nnum_epochs = 50\nfor epoch in range(num_epochs):\n    epoch_start_time = time.time()  # Start time for the epoch\n    \n    model.train()  # Set the model to training mode\n    running_loss = 0.0\n    corrects_train = 0\n    total_train = 0\n    progress_bar = tqdm(train_loader, desc=f'Epoch {epoch+1}/{num_epochs}')\n    for inputs, labels in progress_bar:\n        inputs, labels = inputs.to(device), labels.to(device).long()  # Convert labels to int64\n\n        optimizer.zero_grad()  # Zero the parameter gradients\n        outputs = model(inputs)  # Forward pass\n        loss = criterion(outputs, labels)  # Calculate loss\n        loss.backward()  # Backward pass\n        optimizer.step()  # Optimize the model parameters\n\n        running_loss += loss.item() * inputs.size(0)\n\n        _, preds = torch.max(outputs, 1)\n        corrects_train += torch.sum(preds == labels.data)\n        total_train += labels.size(0)\n        \n        progress_bar.set_postfix(loss=loss.item())\n\n    epoch_loss = running_loss / len(train_loader.dataset)\n    train_acc = corrects_train.double() / total_train\n    train_losses.append(epoch_loss)\n    train_accuracies.append(train_acc.item())\n    print(f'Epoch {epoch+1}/{num_epochs}, Training Loss: {epoch_loss:.4f}, Training Accuracy: {train_acc:.4f}')\n\n    model.eval()  # Set the model to evaluation mode\n    val_loss = 0.0\n    corrects_val = 0\n    with torch.no_grad():\n        for inputs, labels in val_loader:\n            inputs, labels = inputs.to(device), labels.to(device).long()  # Convert labels to int64\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n            val_loss += loss.item() * inputs.size(0)\n            _, preds = torch.max(outputs, 1)\n            corrects_val += torch.sum(preds == labels.data)\n\n    val_loss = val_loss / len(val_loader.dataset)\n    val_losses.append(val_loss)\n    val_acc = corrects_val.double() / len(val_loader.dataset)\n    val_accuracies.append(val_acc.item())\n    print(f'Validation Loss: {val_loss:.4f}, Validation Accuracy: {val_acc:.4f}')\n\n    # Check for early stopping\n    early_stopping.check_early_stop(val_loss)\n    if early_stopping.early_stop:\n        print(\"Early stopping\")\n        break\n\n    # Step learning rate scheduler\n    lr_scheduler.step(val_loss)\n\n    # Save model checkpoint\n    best_loss = save_checkpoint(model, epoch, val_loss, best_loss)\n    \n    epoch_end_time = time.time()  # End time for the epoch\n    epoch_duration = epoch_end_time - epoch_start_time\n    print(f'Time taken for epoch {epoch+1}: {epoch_duration:.2f} seconds')\n\n# Calculate total training time\nend_time = time.time()\nelapsed_time = end_time - start_time\nformatted_time = str(timedelta(seconds=int(elapsed_time)))\nprint(f'Training time: {formatted_time}')\n\n# Save the final model\ntorch.save(model.state_dict(), 'densenet121_mammogram_final.pth')\nprint(\"Model saved as densenet121_mammogram_final.pth\")","metadata":{"execution":{"iopub.status.busy":"2024-08-06T06:43:08.263156Z","iopub.execute_input":"2024-08-06T06:43:08.263497Z","iopub.status.idle":"2024-08-06T08:16:07.804989Z","shell.execute_reply.started":"2024-08-06T06:43:08.26347Z","shell.execute_reply":"2024-08-06T08:16:07.803599Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Plot training & validation accuracy values\nplt.figure(figsize=(12, 4))\nplt.subplot(1, 2, 1)\nplt.plot(range(1, len(train_accuracies) + 1), train_accuracies, label='Training Accuracy')\nplt.plot(range(1, len(val_accuracies) + 1), val_accuracies, label='Validation Accuracy')\nplt.title('Model Accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.legend(loc='upper left')\nplt.grid(True)\n\n# Plot training & validation loss values\nplt.subplot(1, 2, 2)\nplt.plot(range(1, len(train_losses) + 1), train_losses, label='Training Loss')\nplt.plot(range(1, len(val_losses) + 1), val_losses, label='Validation Loss')\nplt.title('Model Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend(loc='upper left')\nplt.grid(True)\n\nplt.tight_layout()\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-08-06T08:16:07.806948Z","iopub.execute_input":"2024-08-06T08:16:07.807222Z","iopub.status.idle":"2024-08-06T08:16:08.442059Z","shell.execute_reply.started":"2024-08-06T08:16:07.807198Z","shell.execute_reply":"2024-08-06T08:16:08.441164Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Confusion Matrix and Classification Report\nfrom sklearn.metrics import confusion_matrix, classification_report\nimport seaborn as sns\n\nmodel.eval()\nall_preds = []\nall_labels = []\n\nwith torch.no_grad():\n    for inputs, labels in test_loader:\n        inputs, labels = inputs.to(device), labels.to(device).long()\n        outputs = model(inputs)\n        if isinstance(outputs, tuple):  # Check if outputs is a tuple\n            outputs, aux_outputs = outputs\n        _, preds = torch.max(outputs, 1)\n        all_preds.extend(preds.cpu().numpy())\n        all_labels.extend(labels.cpu().numpy())\n\nconf_matrix = confusion_matrix(all_labels, all_preds)\nplt.figure(figsize=(10, 7))\nsns.heatmap(conf_matrix, annot=True, fmt='d', cmap='Blues')\nplt.xlabel('Predicted Label')\nplt.ylabel('True Label')\nplt.title('Confusion Matrix')\nplt.show()\n\nclass_report = classification_report(all_labels, all_preds)\nprint('Classification Report:')\nprint(class_report)\n\n# ROC-AUC Curve\nfrom sklearn.metrics import roc_auc_score, roc_curve, auc\nfrom sklearn.preprocessing import label_binarize\nfrom itertools import cycle\n\nn_classes = len(label_encoder.classes_)\ny_test = label_binarize(all_labels, classes=[*range(n_classes)])\ny_score = model(torch.tensor(test_dataset[:][0].to(device)).float()).cpu().detach().numpy()\n\nfpr = dict()\ntpr = dict()\nroc_auc = dict()\nfor i in range(n_classes):\n    fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_score[:, i])\n    roc_auc[i] = auc(fpr[i], tpr[i])\n\nplt.figure(figsize=(10, 7))\ncolors = cycle(['aqua', 'darkorange', 'cornflowerblue', 'green'])\nfor i, color in zip(range(n_classes), colors):\n    plt.plot(fpr[i], tpr[i], color=color, lw=2,\n             label='ROC curve of class {0} (area = {1:0.2f})'\n                   ''.format(i, roc_auc[i]))\n\nplt.plot([0, 1], [0, 1], 'k--', lw=2)\nplt.xlim([0.0, 1.0])\nplt.ylim([0.0, 1.05])\nplt.xlabel('False Positive Rate')\nplt.ylabel('True Positive Rate')\nplt.title('Receiver Operating Characteristic to multi-class')\nplt.legend(loc=\"lower right\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-08-06T08:16:08.443537Z","iopub.execute_input":"2024-08-06T08:16:08.444055Z","iopub.status.idle":"2024-08-06T08:16:59.260831Z","shell.execute_reply.started":"2024-08-06T08:16:08.444023Z","shell.execute_reply":"2024-08-06T08:16:59.259445Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torchvision.models as models\nimport torch.nn as nn\nfrom sklearn.preprocessing import label_binarize\nfrom sklearn.metrics import classification_report, confusion_matrix, roc_curve, auc\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n# Define the custom DenseNet-121 model\nclass CustomDenseNet121(nn.Module):\n    def __init__(self, num_classes=4):\n        super(CustomDenseNet121, self).__init__()\n        self.densenet = models.densenet121(pretrained=True)\n        self.densenet.classifier = nn.Linear(self.densenet.classifier.in_features, num_classes)\n        \n    def forward(self, x):\n        x = self.densenet(x)\n        return x\n\n# Instantiate and load the model\nnum_classes = 4  # Adjust based on your dataset\nmodel = CustomDenseNet121(num_classes=num_classes)\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = nn.DataParallel(model)\nmodel = model.to(device)\n\n# Load the trained model weights\nmodel.load_state_dict(torch.load('/kaggle/working/densenet121_mammogram_final.pth'))\n\n# Set the model to evaluation mode\nmodel.eval()\n\n# Evaluate the model on the test set and get the probabilities\nall_probs = []\nall_labels = []\n\nwith torch.no_grad():\n    for inputs, labels in test_loader:\n        inputs, labels = inputs.to(device), labels.to(device).long()\n        outputs = model(inputs)\n        probs = torch.nn.functional.softmax(outputs, dim=1)\n        all_probs.extend(probs.cpu().numpy())\n        all_labels.extend(labels.cpu().numpy())\n\n# One-hot encode the labels\nall_labels = label_binarize(all_labels, classes=[0, 1, 2, 3])  # Adjust the classes based on your dataset\nall_probs = np.array(all_probs)\n\n# Generate the classification report\nreport = classification_report(all_labels.argmax(axis=1), all_probs.argmax(axis=1), target_names=['Class A', 'Class B', 'Class C', 'Class D'])\nprint(report)\n\n# Generate the confusion matrix\nconf_matrix = confusion_matrix(all_labels.argmax(axis=1), all_probs.argmax(axis=1))\n\n# Function to calculate sensitivity and specificity\ndef calculate_sensitivity_specificity(conf_matrix):\n    sensitivity = dict()\n    specificity = dict()\n    for i in range(len(conf_matrix)):\n        TP = conf_matrix[i, i]\n        FN = np.sum(conf_matrix[i, :]) - TP\n        FP = np.sum(conf_matrix[:, i]) - TP\n        TN = np.sum(conf_matrix) - (TP + FN + FP)\n        \n        sensitivity[i] = TP / (TP + FN) if (TP + FN) > 0 else 0\n        specificity[i] = TN / (TN + FP) if (TN + FP) > 0 else 0\n        \n    return sensitivity, specificity\n\n# Calculate sensitivity and specificity\nsensitivity, specificity = calculate_sensitivity_specificity(conf_matrix)\n\n# Display the results\nprint(\"Sensitivity (Recall) for each class:\")\nfor i in range(len(sensitivity)):\n    print(f\"Class {i}: {sensitivity[i]:.4f}\")\n\nprint(\"\\nSpecificity for each class:\")\nfor i in range(len(specificity)):\n    print(f\"Class {i}: {specificity[i]:.4f}\")\n\n# Plot the confusion matrix as a heatmap\nplt.figure(figsize=(10, 7))\nsns.heatmap(conf_matrix, annot=True, fmt='d', cmap='Blues', xticklabels=['Class A', 'Class B', 'Class C', 'Class D'], yticklabels=['Class A', 'Class B', 'Class C', 'Class D'])\nplt.xlabel('Predicted')\nplt.ylabel('True')\nplt.title('Confusion Matrix')\nplt.show()\n\n# Compute ROC curve and ROC area for each class\nfpr = dict()\ntpr = dict()\nroc_auc = dict()\n\nfor i in range(num_classes):\n    fpr[i], tpr[i], _ = roc_curve(all_labels[:, i], all_probs[:, i])\n    roc_auc[i] = auc(fpr[i], tpr[i])\n\n# Compute micro-average ROC curve and ROC area\nfpr[\"micro\"], tpr[\"micro\"], _ = roc_curve(all_labels.ravel(), all_probs.ravel())\nroc_auc[\"micro\"] = auc(fpr[\"micro\"], tpr[\"micro\"])\n\n# Plot ROC curve for each class\nplt.figure(figsize=(10, 7))\ncolors = ['aqua', 'darkorange', 'cornflowerblue', 'green']\nfor i, color in zip(range(num_classes), colors):\n    plt.plot(fpr[i], tpr[i], color=color, lw=2, label=f'ROC curve of class {i} (area = {roc_auc[i]:0.2f})')\n\nplt.plot([0, 1], [0, 1], 'k--', lw=2)\nplt.xlim([0.0, 1.0])\nplt.ylim([0.0, 1.05])\nplt.xlabel('False Positive Rate')\nplt.ylabel('True Positive Rate')\nplt.title('Receiver Operating Characteristic (ROC) Curve')\nplt.legend(loc=\"lower right\")\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-08-06T08:21:47.593945Z","iopub.execute_input":"2024-08-06T08:21:47.594529Z","iopub.status.idle":"2024-08-06T08:22:34.044456Z","shell.execute_reply.started":"2024-08-06T08:21:47.594486Z","shell.execute_reply":"2024-08-06T08:22:34.043627Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torchvision.models import densenet121\nfrom collections import OrderedDict\n\nclass CustomDenseNet121(nn.Module):\n    def __init__(self, num_classes):\n        super(CustomDenseNet121, self).__init__()\n        self.densenet = densenet121(weights='IMAGENET1K_V1')\n        num_ftrs = self.densenet.classifier.in_features\n        self.densenet.classifier = nn.Linear(num_ftrs, num_classes)\n    \n    def forward(self, x):\n        x = self.densenet(x)\n        return x\n\n# Instantiate the model\nnum_classes = 4  # Adjust based on your dataset\nmodel = CustomDenseNet121(num_classes=num_classes)\n\n# Load the state_dict with removed `module.` prefix\nstate_dict = torch.load('densenet121_mammogram_final.pth')\nnew_state_dict = OrderedDict()\nfor k, v in state_dict.items():\n    name = k[7:] if k.startswith('module.') else k  # remove 'module.' prefix\n    new_state_dict[name] = v\n\nmodel.load_state_dict(new_state_dict)\n\n# Move model to the appropriate device\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nmodel = model.to(device)\n\n# Set model to evaluation mode\nmodel.eval()\n\n# Now, you can proceed with the prediction as planned\nimport pandas as pd\nfrom PIL import Image\nfrom torchvision import transforms\n\n# Load your test data\ntest_data = pd.read_csv('/kaggle/working/test_set-v2.csv')\n\n# Define the image transformation\ntransform = transforms.Compose([\n    transforms.Resize((256, 256)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n# Function to load and transform image\ndef load_image(image_path):\n    image = Image.open(image_path).convert('RGB')\n    image = transform(image).unsqueeze(0)  # Add batch dimension\n    return image\n\n# Define the path to the images\nimage_directory = '/kaggle/input/rsna-breast-cancer-256-pngs'\n\n# Making predictions on the test dataset\npredictions = []\nfor idx, row in test_data.iterrows():\n    patient_id = row['patient_id']\n    image_id = row['image_id']\n    image_path = f\"{image_directory}/{patient_id}_{image_id}.png\"\n    image = load_image(image_path).to(device)\n    with torch.no_grad():\n        output = model(image)\n        _, predicted = torch.max(output, 1)\n        predictions.append(predicted.item())\n\n# Add predictions to the test_data dataframe\ntest_data['predicted_density'] = predictions\n\n# Save the predictions to a new CSV file\ntest_data.to_csv('test_predictions.csv', index=False)\n","metadata":{"execution":{"iopub.status.busy":"2024-08-06T08:51:17.995227Z","iopub.execute_input":"2024-08-06T08:51:17.99558Z","iopub.status.idle":"2024-08-06T08:53:14.076393Z","shell.execute_reply.started":"2024-08-06T08:51:17.995539Z","shell.execute_reply":"2024-08-06T08:53:14.075442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torchvision.models import densenet121\nfrom collections import OrderedDict\nimport pandas as pd\nfrom PIL import Image\nfrom torchvision import transforms\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nclass CustomDenseNet121(nn.Module):\n    def __init__(self, num_classes):\n        super(CustomDenseNet121, self).__init__()\n        self.densenet = densenet121(weights='IMAGENET1K_V1')\n        num_ftrs = self.densenet.classifier.in_features\n        self.densenet.classifier = nn.Linear(num_ftrs, num_classes)\n    \n    def forward(self, x):\n        x = self.densenet(x)\n        return x\n\n# Instantiate the model\nnum_classes = 4  # Adjust based on your dataset\nmodel = CustomDenseNet121(num_classes=num_classes)\n\n# Load the state_dict with removed `module.` prefix\nstate_dict = torch.load('densenet121_mammogram_final.pth')\nnew_state_dict = OrderedDict()\nfor k, v in state_dict.items():\n    name = k[7:] if k.startswith('module.') else k  # remove 'module.' prefix\n    new_state_dict[name] = v\n\nmodel.load_state_dict(new_state_dict)\n\n# Move model to the appropriate device\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nmodel = model.to(device)\n\n# Set model to evaluation mode\nmodel.eval()\n\n# Load your test data\ntest_data = pd.read_csv('/kaggle/working/test_set-v2.csv')\n\n# Define the image transformation\ntransform = transforms.Compose([\n    #transforms.Resize((256, 256)),\n    transforms.ToTensor(),\n    #transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n# Function to load and transform image\ndef load_image(image_path):\n    image = Image.open(image_path).convert('RGB')\n    image = transform(image).unsqueeze(0)  # Add batch dimension\n    return image\n\n# Define the path to the images\nimage_directory = '/kaggle/input/rsna-breast-cancer-256-pngs'\n\n# Making predictions on the test dataset\npredictions = []\nconfidences = []\nfor idx, row in test_data.iterrows():\n    patient_id = str(int(row['patient_id']))\n    image_id = str(int(row['image_id']))\n    image_path = f\"{image_directory}/{patient_id}_{image_id}.png\"\n    print(f\"Processing {image_path}\")  # Print the image path for debugging\n    try:\n        image = load_image(image_path).to(device)\n        with torch.no_grad():\n            output = model(image)\n            probabilities = nn.functional.softmax(output, dim=1)\n            confidence, predicted = torch.max(probabilities, 1)\n            predictions.append(predicted.item())\n            confidences.append(confidence.item())\n    except FileNotFoundError:\n        print(f\"File not found: {image_path}\")\n        predictions.append(None)\n        confidences.append(None)\n\n# Add predictions and confidences to the test_data dataframe\ntest_data['predicted_density'] = predictions\ntest_data['confidence'] = confidences\n\n# Save the predictions to a new CSV file\ntest_data.to_csv('test_predictions_with_confidence.csv', index=False)\n\n# Display some images with their predictions and confidence scores\ndef imshow(img, title=None):\n    img = img / 2 + 0.5  # unnormalize\n    npimg = img.numpy()\n    plt.imshow(np.transpose(npimg, (1, 2, 0)))\n    if title:\n        plt.title(title)\n    plt.show()\n\n# Display the first few images with their predictions and confidence scores\nfor idx in range(5):  # Adjust the range as needed\n    row = test_data.iloc[idx]\n    patient_id = str(int(row['patient_id']))\n    image_id = str(int(row['image_id']))\n    predicted_density = row['predicted_density']\n    confidence = row['confidence']\n    image_path = f\"{image_directory}/{patient_id}_{image_id}.png\"\n    try:\n        image = load_image(image_path).squeeze(0)  # Remove batch dimension\n        title = f\"Pred: {predicted_density}, Conf: {confidence:.2f}\"\n        imshow(image.cpu(), title=title)\n    except FileNotFoundError:\n        print(f\"File not found: {image_path}\")\n","metadata":{"execution":{"iopub.status.busy":"2024-08-06T09:14:29.63794Z","iopub.execute_input":"2024-08-06T09:14:29.638649Z","iopub.status.idle":"2024-08-06T09:16:27.906459Z","shell.execute_reply.started":"2024-08-06T09:14:29.638611Z","shell.execute_reply":"2024-08-06T09:16:27.90558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}