{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"pip install torch-geometric","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:57:55.403949Z","iopub.execute_input":"2023-05-17T17:57:55.404392Z","iopub.status.idle":"2023-05-17T17:58:23.044966Z","shell.execute_reply.started":"2023-05-17T17:57:55.404353Z","shell.execute_reply":"2023-05-17T17:58:23.043694Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\nimport os\nimport numpy as np\nimport pandas as pd\nfrom glob import glob\nfrom PIL import Image\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom skimage.io import imread\n\n# Pytorch Libraries\nimport torch\nimport torchvision\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nfrom torch_geometric.nn import GCNConv, BatchNorm\nimport torch_geometric.transforms as T\nimport torch_geometric\n\nfrom torch.optim import lr_scheduler\nfrom torchvision import models, transforms\nfrom torchvision.datasets import ImageFolder\nfrom torch.utils.data import TensorDataset, DataLoader, Dataset\n\nfrom sklearn.model_selection import train_test_split, GridSearchCV\nfrom sklearn.calibration import CalibratedClassifierCV\nfrom sklearn.ensemble import BaggingClassifier\nfrom sklearn.metrics import confusion_matrix, roc_curve, roc_auc_score\nfrom sklearn.metrics import classification_report, roc_curve, roc_auc_score, confusion_matrix, precision_recall_curve, auc\nfrom scikitplot.metrics import plot_roc_curve, plot_confusion_matrix\nfrom sklearn.metrics import precision_score\nfrom sklearn.metrics import recall_score\nfrom sklearn.metrics import f1_score\nfrom sklearn.svm import SVC\n\nsns.set()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-05-17T17:58:23.048666Z","iopub.execute_input":"2023-05-17T17:58:23.049375Z","iopub.status.idle":"2023-05-17T17:58:28.692307Z","shell.execute_reply.started":"2023-05-17T17:58:23.049340Z","shell.execute_reply":"2023-05-17T17:58:28.691396Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"meta_data = pd.read_csv('/kaggle/input/histopathologic-cancer-detection/train_labels.csv')\nmeta_data = meta_data.groupby('label', group_keys=False).apply(lambda x: x.sample(2500))\nmeta_data.reset_index(drop=True, inplace=True)\nmeta_data.shape","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:58:28.693715Z","iopub.execute_input":"2023-05-17T17:58:28.694435Z","iopub.status.idle":"2023-05-17T17:58:29.148337Z","shell.execute_reply.started":"2023-05-17T17:58:28.694398Z","shell.execute_reply":"2023-05-17T17:58:29.147254Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"meta_data.head()","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:58:29.154002Z","iopub.execute_input":"2023-05-17T17:58:29.156776Z","iopub.status.idle":"2023-05-17T17:58:29.175266Z","shell.execute_reply.started":"2023-05-17T17:58:29.156737Z","shell.execute_reply":"2023-05-17T17:58:29.174323Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"base_dir = os.path.join('..', 'input/histopathologic-cancer-detection/train')\n\nimageid_path_dict = {os.path.splitext(os.path.basename(x))[0]: x \n                     for x in glob(os.path.join(base_dir,'*.tif'))}\n\nmeta_data['path'] = meta_data['id'].map(imageid_path_dict.get)\nmeta_data.head()","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:58:29.179625Z","iopub.execute_input":"2023-05-17T17:58:29.182654Z","iopub.status.idle":"2023-05-17T17:58:33.012683Z","shell.execute_reply.started":"2023-05-17T17:58:29.182619Z","shell.execute_reply":"2023-05-17T17:58:33.011723Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_samples = 6\nn_classes = len(meta_data['label'].unique())\ndf = meta_data.sort_values(['label']).groupby('label')\nfig, axs = plt.subplots(n_classes, n_samples, figsize = (10, 4))\nfor ax, (type_, rows) in zip(axs, df):\n    ax[0].set_title('Class: '+ str(type_), fontsize=15)\n    for sub_ax, (_, subset) in zip(ax, rows.sample(n_samples).iterrows()):\n        img = imread(subset['path'])\n        sub_ax.imshow(img)\n        sub_ax.axis('off')","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:58:33.014052Z","iopub.execute_input":"2023-05-17T17:58:33.014940Z","iopub.status.idle":"2023-05-17T17:58:34.266258Z","shell.execute_reply.started":"2023-05-17T17:58:33.014904Z","shell.execute_reply":"2023-05-17T17:58:34.265131Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data = []\noutliers = []\nfor path in meta_data['path']:\n    img = cv2.imread(path)\n        \n    avgR = np.mean(img[:,:,2])\n    avgG = np.mean(img[:,:,1])\n    avgB = np.mean(img[:,:,0])\n    RGB = np.mean([avgR, avgG, avgB])\n    \n    data.append([avgR, avgG, avgB, RGB])\n    \n    if ((RGB <= 45) or (RGB >= 245)) : outliers.append(meta_data.loc[meta_data['path'] == path].index[0])\n    \nrgb = pd.DataFrame(data, columns=['Red Channel Mean','Green Channel Mean','Blue Channel Mean', 'RGB Mean'])\n\nmeta_data = pd.concat([meta_data.reset_index(drop=True), rgb], axis=1)","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:58:34.267279Z","iopub.execute_input":"2023-05-17T17:58:34.267857Z","iopub.status.idle":"2023-05-17T17:59:25.328113Z","shell.execute_reply.started":"2023-05-17T17:58:34.267821Z","shell.execute_reply":"2023-05-17T17:59:25.327145Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(outliers)","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:59:36.293262Z","iopub.execute_input":"2023-05-17T17:59:36.293797Z","iopub.status.idle":"2023-05-17T17:59:36.299964Z","shell.execute_reply.started":"2023-05-17T17:59:36.293764Z","shell.execute_reply":"2023-05-17T17:59:36.298872Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"extremely_low_pxl_img = meta_data[meta_data['RGB Mean'] <= 45]\nextremely_high_pxl_img = meta_data[meta_data['RGB Mean'] >= 245]","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:59:36.304226Z","iopub.execute_input":"2023-05-17T17:59:36.304859Z","iopub.status.idle":"2023-05-17T17:59:36.315753Z","shell.execute_reply.started":"2023-05-17T17:59:36.304825Z","shell.execute_reply":"2023-05-17T17:59:36.314828Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_samples = 5\ndf = extremely_high_pxl_img.sort_values(['label']).groupby('label')\nfig, axs = plt.subplots(2, n_samples, figsize = (10, 4))\nfor ax, (type_, rows) in zip(axs, df):\n    ax[0].set_title('Class: '+ str(type_), fontsize=15)\n    for sub_ax, (_, subset) in zip(ax, rows.sample(n_samples, replace = True).iterrows()):\n        img = imread(subset['path'])\n        sub_ax.imshow(img)\n        sub_ax.axis('off')","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:59:36.317042Z","iopub.execute_input":"2023-05-17T17:59:36.319040Z","iopub.status.idle":"2023-05-17T17:59:37.669762Z","shell.execute_reply.started":"2023-05-17T17:59:36.319008Z","shell.execute_reply":"2023-05-17T17:59:37.668765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_samples = 5\ndf = extremely_low_pxl_img.sort_values(['label']).groupby('label')\nfig, axs = plt.subplots(2, n_samples, figsize = (10, 4))\nfor ax, (type_, rows) in zip(axs, df):\n    ax[0].set_title('Class: '+ str(type_), fontsize=15)\n    for sub_ax, (_, subset) in zip(ax, rows.sample(n_samples, replace = True).iterrows()):\n        img = imread(subset['path'])\n        sub_ax.imshow(img)\n        sub_ax.axis('off')","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:59:37.671234Z","iopub.execute_input":"2023-05-17T17:59:37.671855Z","iopub.status.idle":"2023-05-17T17:59:38.966150Z","shell.execute_reply.started":"2023-05-17T17:59:37.671820Z","shell.execute_reply":"2023-05-17T17:59:38.965198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"meta_data = meta_data.drop(outliers)\nmeta_data['label'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:59:38.967719Z","iopub.execute_input":"2023-05-17T17:59:38.968326Z","iopub.status.idle":"2023-05-17T17:59:38.979503Z","shell.execute_reply.started":"2023-05-17T17:59:38.968289Z","shell.execute_reply":"2023-05-17T17:59:38.978383Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomDataset(Dataset):\n    def __init__(self, data_df, transform=None):\n        self.data_df = data_df\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.data_df)\n\n    def __getitem__(self, index):\n        img_path = self.data_df.iloc[index]['path']\n        label = self.data_df.iloc[index]['label']\n        \n        # Load image from file\n        img = Image.open(img_path).convert('RGB')\n        \n        if self.transform is not None:\n            img = self.transform(img)\n        \n        return img, label\n\n# Split data into train and test sets\ntrain_df, test_df = train_test_split(meta_data, test_size=0.2, random_state=42)","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:59:38.981298Z","iopub.execute_input":"2023-05-17T17:59:38.981709Z","iopub.status.idle":"2023-05-17T17:59:38.993344Z","shell.execute_reply.started":"2023-05-17T17:59:38.981676Z","shell.execute_reply":"2023-05-17T17:59:38.992126Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the batch size\nbatch_size = 32","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:59:38.995138Z","iopub.execute_input":"2023-05-17T17:59:38.995519Z","iopub.status.idle":"2023-05-17T17:59:39.002552Z","shell.execute_reply.started":"2023-05-17T17:59:38.995485Z","shell.execute_reply":"2023-05-17T17:59:39.001561Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the data transforms for training and testing datasets\ntrain_transforms = transforms.Compose([\n    transforms.RandomResizedCrop(size=256, scale=(0.8, 1.0)),\n    transforms.RandomRotation(degrees=15),\n    transforms.RandomHorizontalFlip(),\n    transforms.CenterCrop(size=224),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                         std=[0.229, 0.224, 0.225])\n])\n\ntest_transforms = transforms.Compose([\n    transforms.Resize(size=256),\n    transforms.CenterCrop(size=224),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                         std=[0.229, 0.224, 0.225])\n])\n\n# Load the data\ntrain_dataset = CustomDataset(train_df, transform=train_transforms)\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n\ntest_dataset = CustomDataset(test_df, transform=test_transforms)\ntest_loader = DataLoader(test_dataset, batch_size=batch_size)","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:59:39.004179Z","iopub.execute_input":"2023-05-17T17:59:39.004701Z","iopub.status.idle":"2023-05-17T17:59:39.016521Z","shell.execute_reply.started":"2023-05-17T17:59:39.004666Z","shell.execute_reply":"2023-05-17T17:59:39.014798Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def evaluate1(model, loader, criterion):\n    correct = 0\n    total = 0\n    total_loss = 0\n    \n    model.eval()\n    with torch.no_grad():\n        for data in loader:\n            images, labels = data\n            images = images.to(device)\n            labels = labels.to(device)\n            outputs = model(images)\n            loss = criterion(outputs.squeeze(), labels.float())\n            total_loss += loss.item()\n            predicted = torch.round(torch.sigmoid(outputs))\n            total += labels.size(0)\n            correct += (predicted == labels.unsqueeze(1)).sum().item()\n\n    acc = correct / total\n    avg_loss = total_loss / len(loader)\n    model.train()\n    return acc, avg_loss","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:59:39.017865Z","iopub.execute_input":"2023-05-17T17:59:39.018935Z","iopub.status.idle":"2023-05-17T17:59:39.030757Z","shell.execute_reply.started":"2023-05-17T17:59:39.018897Z","shell.execute_reply":"2023-05-17T17:59:39.029752Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# define hyperparameters\nlearning_rate = 0.001\nnum_epochs = 20\nroc_aucs = []\n\n# define binary cross entropy loss\ncriterion = nn.BCEWithLogitsLoss()\n\n# define ResNet50, VGG19, Inception, and DenseNet121 models\nmodels_dict = {'VGG16': models.vgg16(weights='DEFAULT')}\n\n# define empty lists to store accuracy and loss\naccs = []\nlosses = []\n\n# loop over models\nfor model_name, model in models_dict.items():\n    \n    print('Training', model_name, 'model')\n    \n    if (model_name == 'VGG19') | (model_name == 'VGG16'):\n        num_features = model.classifier[-1].in_features\n        model.classifier[-1] = nn.Linear(num_features, 512)\n        model.classifier.add_module('bn1', nn.BatchNorm1d(512))\n        model.classifier.add_module('relu1', nn.ReLU(inplace=True))\n        model.classifier.add_module('dropout1', nn.Dropout())\n        model.classifier.add_module('fc2', nn.Linear(512, 256))\n        model.classifier.add_module('bn2', nn.BatchNorm1d(256))\n        model.classifier.add_module('relu2', nn.ReLU(inplace=True))\n        model.classifier.add_module('dropout2', nn.Dropout())\n        model.classifier.add_module('fc3', nn.Linear(256, 1))\n#     else:\n#         if model_name == 'DenseNet121':\n#             num_ftrs = model.classifier.in_features\n#             model.classifier = nn.Sequential(\n#                 nn.Linear(num_ftrs, 512),\n#                 nn.BatchNorm1d(512),\n#                 nn.ReLU(inplace=True),\n#                 nn.Dropout(),\n#                 nn.Linear(512, 256),\n#                 nn.BatchNorm1d(256),\n#                 nn.ReLU(inplace=True),\n#                 nn.Dropout(),\n#                 nn.Linear(256, 1)\n#             )\n#         else:\n#             num_ftrs = model.fc.in_features\n#             model.fc = nn.Sequential(\n#                 nn.Linear(num_ftrs, 512),\n#                 nn.BatchNorm1d(512),\n#                 nn.ReLU(inplace=True),\n#                 nn.Dropout(),\n#                 nn.Linear(512, 256),\n#                 nn.BatchNorm1d(256),\n#                 nn.ReLU(inplace=True),\n#                 nn.Dropout(),\n#                 nn.Linear(256, 1)\n#             )\n\n    model.to(device)\n    print(model)\n    # define optimizer\n    optimizer = optim.Adam(model.parameters(), lr=learning_rate)\n    scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=3)\n    \n    # define empty lists to store predictions and labels\n    y_preds = []\n    y_trues = []\n    # train the model\n    for epoch in range(num_epochs):\n        \n        running_loss = 0.0\n        total = 0\n        correct = 0\n        \n        for i, (inputs, labels) in enumerate(train_loader):\n            inputs, labels = inputs.to(device), labels.to(device)\n            \n            # zero the parameter gradients\n            optimizer.zero_grad()\n\n            # forward + backward + optimize\n            outputs = model(inputs)\n            loss = criterion(outputs, labels.float().unsqueeze(1))\n            loss.backward()\n            nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)\n            optimizer.step()\n\n            # calculate accuracy\n            total += labels.size(0)\n            predicted = torch.round(torch.sigmoid(outputs))\n            correct += (predicted == labels.unsqueeze(1)).sum().item()\n            acc = correct / total\n\n            # append accuracy and loss to the lists\n            accs.append(acc)\n            losses.append(loss.item())\n\n            # append predictions and labels to the lists\n            y_preds += predicted.cpu().detach().numpy().tolist()\n            y_trues += labels.cpu().detach().numpy().tolist()\n\n        print('Epoch [{}/{}], Loss: {:.4f}, Accuracy: {:.2f}%'\n              .format(epoch+1, num_epochs, loss.item(), acc*100))\n        \n        # calculate validation accuracy and loss\n        val_acc, val_loss = evaluate1(model, test_loader, criterion)\n        print('Accuracy of the network on the validation set: %d %%' % (100 * val_acc))\n\n        # adjust learning rate based on validation loss\n        scheduler.step(val_loss)\n        \n    torch.save(model.state_dict(), model_name + '.pt')\n\n# Plot AUC ROC Curve\nfig, axs = plt.subplots(2, 2, figsize=(10, 8))\naxs = axs.ravel()\nfor i, (name, model) in enumerate(models_dict.items()):\n    model.eval()\n    y_score = []\n    y_true = []\n    with torch.no_grad():\n        for inputs, labels in test_loader:\n            inputs = inputs.to(device)\n            labels = labels.to(device)\n            model = model.to(device)\n            outputs = model(inputs)\n            outputs = torch.sigmoid(outputs)\n            y_score.extend(outputs.cpu().numpy()[:, 0])\n            y_true.extend(labels.cpu().numpy())\n\n    fpr, tpr, _ = roc_curve(y_true, y_score)\n    roc_auc = auc(fpr, tpr)\n\n    axs[i].plot(fpr, tpr, label=f'ROC curve (AUC = {roc_auc:.2f})')\n    axs[i].plot([0, 1], [0, 1], 'k--')\n    axs[i].set_xlabel('False Positive Rate')\n    axs[i].set_ylabel('True Positive Rate')\n    axs[i].set_title(name)\n    axs[i].legend(loc=\"lower right\")\n    plt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-05-17T17:59:39.032497Z","iopub.execute_input":"2023-05-17T17:59:39.032923Z","iopub.status.idle":"2023-05-17T18:18:14.246646Z","shell.execute_reply.started":"2023-05-17T17:59:39.032888Z","shell.execute_reply":"2023-05-17T18:18:14.245758Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot Confusion Matrix\nfig, axs = plt.subplots(2, 2, figsize=(10, 8))\naxs = axs.ravel()\n\n# Loop through each model and plot its confusion matrix in a subplot\nfor i, (name, model) in enumerate(models_dict.items()):\n    model.eval()\n    y_pred = []\n    y_true = []\n    threshold = 0.5\n    with torch.no_grad():\n        for inputs, labels in test_loader:\n            inputs = inputs.to(device)\n            labels = labels.to(device)\n            model = model.to(device)\n            outputs = model(inputs)\n            outputs = torch.sigmoid(outputs)\n            output_numpy = outputs.cpu().numpy()\n            lab = (output_numpy >= threshold).astype(int)\n            y_pred.extend(lab.tolist())\n            y_true.extend(labels.cpu().numpy())\n            \n    y_pred = list(np.array(y_pred).flat)\n    ax = axs[i]\n    cm = confusion_matrix(y_true, y_pred)\n    sns.heatmap(cm, annot=True, cmap=\"Blues\", ax=ax, fmt=\"g\")\n    ax.set_title(\"Confusion Matrix - {}\".format(name))\n    ax.set_xlabel(\"Predicted Labels\")\n    ax.set_ylabel(\"True Labels\")\n\n# Adjust spacing between subplots\nplt.subplots_adjust(hspace=0.3, wspace=0.3)\n\n# Show the plot\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-05-17T14:27:16.305790Z","iopub.execute_input":"2023-05-17T14:27:16.306330Z","iopub.status.idle":"2023-05-17T14:27:22.841050Z","shell.execute_reply.started":"2023-05-17T14:27:16.306296Z","shell.execute_reply":"2023-05-17T14:27:22.840117Z"},"trusted":true},"execution_count":null,"outputs":[]}]}