{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import torch\nimport pandas as pd\nfrom sklearn.model_selection import train_test_split\nimport os\nimport cv2\nimport math\nimport random\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport nibabel as nib\nimport torchvision\nimport torch.nn as nn\nimport torch.optim as optim\nfrom skimage import io\nimport skimage\nimport openslide\nfrom torch.optim import lr_scheduler, Adam, SGD\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.autograd import Variable\nimport torchvision\nfrom torchvision import datasets, models, transforms\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\ndevice","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## On your internet setting for this block only","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install imagecodecs\n# !pip uninstall tifffile","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Loading data paths ","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"BASE_PATH='../input/prostate-cancer-grade-assessment/'\nTRAIN_IMAGES_PATH = BASE_PATH + 'train_images/'\nTRAIN_LABELS_PATH = BASE_PATH + 'train_label_masks/'\nTEST_IMAGES_PATH = BASE_PATH+'test_images'\nSAMPLE = BASE_PATH+'sample_submission.csv'\nTRAIN=BASE_PATH+'train.csv'\nTEST = BASE_PATH+'test.csv'\n\ntrain_df = pd.read_csv(TRAIN)\ntrain = train_df.copy()\ntest_df = pd.read_csv(TEST)\ntest = test_df.copy()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"masks=os.listdir(BASE_PATH+'train_label_masks/')\nimages=os.listdir(BASE_PATH+'train_images/')\ndf_masks=pd.Series(masks).to_frame()\ndf_masks.columns=['mask_file_name']\ndf_masks['image_id']=df_masks.mask_file_name.apply(lambda x:x.split('_')[0])\ndf_train=pd.merge(train,df_masks,on='image_id',how='outer')\ndel df_masks","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Processing gleason score value 'negative'","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"gleason_replace_dict = {0:0, 1:1, 3:2, 4:3, 5:4}\n\ndef process_gleason(gleason):\n    if gleason == 'negative': gs = (1, 1)\n    else: gs = tuple(gleason.split('+'))\n    return [gleason_replace_dict[int(g)] for g in gs]\n\ndf_train.gleason_score = df_train.gleason_score.apply(process_gleason)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train['gleason_primary'] = ''\ndf_train['gleason_secondary'] = ''\n\nfor idx in range(0, len(df_train.gleason_score)):\n    df_train['gleason_primary'][idx] = df_train['gleason_score'][idx][0]\n    df_train['gleason_secondary'][idx] = df_train['gleason_score'][idx][1]\n    \ndf_train = df_train.drop(['gleason_score'], axis=1)\n# df_train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Removing mask values","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train['mask_file_name'].isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train.dropna(subset=['mask_file_name'], inplace=True, axis=0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Train-Test Split","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"X = df_train.drop(['isup_grade'], axis=1)\nY= df_train['mask_file_name']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train, X_valid, y_train, y_valid = train_test_split(X ,Y, test_size=0.2, random_state=1234)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Making Image patches of dimension 224x224 to reduce memory issues and increase accuracy","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def patching(img, tile_size = (224, 224), offset = (224, 224)):\n    img_shape = img.shape\n    patches_list = []\n    for i in range(int(math.ceil(img_shape[0]/(offset[1] * 1.0)))):\n        for j in range(int(math.ceil(img_shape[1]/(offset[0] * 1.0)))):\n            cropped_image = img[offset[1]*i:min(offset[1]*i+tile_size[1], img_shape[0]), offset[0]*j:min(offset[0]*j+tile_size[0], img_shape[1])]\n            cropped_img = cropped_image.astype(np.float32)\n            patches_list.append(cropped_img)\n#     print('make the patches and convert them to float')\n    image = np.array(patches_list)\n    return image ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def prePatch(file_path):\n    image = skimage.io.MultiImage(file_path)[-1]\n    x = patching(image, tile_size = (224, 224), offset = (224, 224))\n    return x","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Making dataloader class","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"\nclass TrainDataset(Dataset):\n    def __init__(self, df, labels, transform = None):\n        self.df = df\n        self.labels = labels\n        self.transform = transform\n        \n    def __len__(self):\n        return len(self.df)\n\n\n    def __getitem__(self, idx):\n        file_name = self.df['image_id'].values[idx]\n        file_name_label = self.labels.values[idx]\n        file_path = f'../input/prostate-cancer-grade-assessment/train_images/{file_name}.tiff'\n        file_path_label = f'../input/prostate-cancer-grade-assessment/train_label_masks/{file_name_label}'\n        image = skimage.io.MultiImage(file_path)[-1]\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        image = cv2.resize(image, (1120, 1120))\n        skimage.io.imsave(\"biopsy.png\", image)\n#         print('image reading now moving to patching')\n        image = prePatch('../working/biopsy.png')\n        \n        label = skimage.io.MultiImage(file_path_label)[-1]\n        label = cv2.resize(label, (1120, 1120))\n        skimage.io.imsave(\"biopsy_label.png\", label)\n        label = prePatch('../working/biopsy_label.png')\n        \n#         new_image=[]\n#         new_label =[]\n        \n#         for i in range(len(image)):\n#             if(len(np.unique(image[i]))!=1):\n                \n#                 new_image.append(image[i])\n#                 new_label.append(label[i])\n        \n\n#         print(\">> new image , new label\",len(new_image), \" , \", len(new_label))\n#         image = np.array(new_image)\n#         label = np.array(new_label)\n#         print(\">> new image , new label\",image.shape, \" , \", label.shape)\n        return image, label","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset = TrainDataset(X_train, y_train, transform= None) \nvalid_dataset = TrainDataset(X_valid, y_valid, transform= None) \ntrain_loader = DataLoader(train_dataset, batch_size=1, num_workers = 0)\nvalid_loader = DataLoader(valid_dataset, batch_size=1, num_workers = 0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Loading a UNet model","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch.nn.functional as F\nclass DoubleConv(nn.Module):\n    \"\"\"(convolution => [BN] => ReLU) * 2\"\"\"\n\n    def __init__(self, in_channels, out_channels, mid_channels=None):\n        super().__init__()\n        if not mid_channels:\n            mid_channels = out_channels\n        self.double_conv = nn.Sequential(\n            nn.Conv2d(in_channels, mid_channels, kernel_size=3, padding=1),\n            nn.BatchNorm2d(mid_channels),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(mid_channels, out_channels, kernel_size=3, padding=1),\n            nn.BatchNorm2d(out_channels),\n            nn.ReLU(inplace=True)\n        )\n\n    def forward(self, x):\n        return self.double_conv(x)\n\n\nclass Down(nn.Module):\n    \"\"\"Downscaling with maxpool then double conv\"\"\"\n\n    def __init__(self, in_channels, out_channels):\n        super().__init__()\n        self.maxpool_conv = nn.Sequential(\n            nn.MaxPool2d(2),\n            DoubleConv(in_channels, out_channels)\n        )\n\n    def forward(self, x):\n        return self.maxpool_conv(x)\n\n\nclass Up(nn.Module):\n    \"\"\"Upscaling then double conv\"\"\"\n\n    def __init__(self, in_channels, out_channels, bilinear=True):\n        super().__init__()\n\n        # if bilinear, use the normal convolutions to reduce the number of channels\n        if bilinear:\n            self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)\n            self.conv = DoubleConv(in_channels, out_channels, in_channels // 2)\n        else:\n            self.up = nn.ConvTranspose2d(in_channels , in_channels // 2, kernel_size=2, stride=2)\n            self.conv = DoubleConv(in_channels, out_channels)\n\n\n    def forward(self, x1, x2):\n        x1 = self.up(x1)\n        # input is CHW\n        diffY = x2.size()[2] - x1.size()[2]\n        diffX = x2.size()[3] - x1.size()[3]\n\n        x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2,\n                        diffY // 2, diffY - diffY // 2])\n        # if you have padding issues, see\n        # https://github.com/HaiyongJiang/U-Net-Pytorch-Unstructured-Buggy/commit/0e854509c2cea854e247a9c615f175f76fbb2e3a\n        # https://github.com/xiaopeng-liao/Pytorch-UNet/commit/8ebac70e633bac59fc22bb5195e513d5832fb3bd\n        x = torch.cat([x2, x1], dim=1)\n        return self.conv(x)\n\n\nclass OutConv(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(OutConv, self).__init__()\n        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1)\n\n    def forward(self, x):\n        return self.conv(x)\nclass UNet(nn.Module):\n    def __init__(self, n_channels, n_classes, bilinear=True):\n        super(UNet, self).__init__()\n        self.n_channels = n_channels\n        self.n_classes = n_classes\n        self.bilinear = bilinear\n\n        self.inc = DoubleConv(n_channels, 64)\n        self.down1 = Down(64, 128)\n        self.down2 = Down(128, 256)\n        self.down3 = Down(256, 512)\n        factor = 2 if bilinear else 1\n        self.down4 = Down(512, 1024 // factor)\n        self.up1 = Up(1024, 512 // factor, bilinear)\n        self.up2 = Up(512, 256 // factor, bilinear)\n        self.up3 = Up(256, 128 // factor, bilinear)\n        self.up4 = Up(128, 64, bilinear)\n        self.outc = OutConv(64, n_classes)\n\n    def forward(self, x):\n        x1 = self.inc(x)\n        x2 = self.down1(x1)\n        x3 = self.down2(x2)\n        x4 = self.down3(x3)\n        x5 = self.down4(x4)\n        x = self.up1(x5, x4)\n        x = self.up2(x, x3)\n        x = self.up3(x, x2)\n        x = self.up4(x, x1)\n        logits = self.outc(x)\n        return logits","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = UNet(n_channels=3, n_classes=3)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Setting optimizers and hyperparamaters","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"criterion = nn.BCEWithLogitsLoss()\noptimizer = optim.SGD(model.parameters(), lr=0.02, momentum=0.5)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def dice_loss(inputs, target):\n    inputs = torch.sigmoid(inputs)\n    smooth = 1.\n    iflat = inputs.contiguous().view(-1)\n    tflat = target.contiguous().view(-1)\n    intersection = (iflat * tflat).sum()\n    loss = 1 - ((2. * intersection + smooth) / (iflat.sum() + tflat.sum() + smooth))\n    return loss","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Training","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"num_epochs = 30\nmodel.to(device)\nhistory = []\n\nprint('Epoch has started') \n\nfor epoch in range(num_epochs): \n    train_loss_total = 0.0 \n    valid_loss_total = 0.0 \n    tot = 0\n    tot_train = 0\n    lossV = 0\n    lossL = 0\n      \n    for images, labels in iter(train_loader):\n        for i in range(len(images)):\n            \n            image = images[i].to(device)\n            label = labels[i].to(device) \n\n            image = image.type(torch.cuda.FloatTensor)\n            label = label.type(torch.cuda.FloatTensor)\n\n            image = image.permute(0,3,2,1)\n            label = label.permute(0,3,2,1)\n\n            outputs = model(image)\n            loss = criterion(outputs, label) \n            loss.backward() \n            optimizer.step() \n    #       pred = (outputs > 0.5).float()\n    #       lossL += dice_coeff(pred, label).item()\n            lossL = dice_loss(outputs, label)\n    #       tot_train += lossL.item() * data.size(0)\n            train_loss_total  += loss.item()\n        break\n\n    for datas, labels in iter(valid_loader):\n        for i in range(len(datas)):\n            data = datas[i].to(device)\n            label = labels[i].to(device)\n\n            data = data.type(torch.cuda.FloatTensor)\n            label = label.type(torch.cuda.FloatTensor)\n\n            data = data.permute(0,3,2,1)\n            label = label.permute(0,3,2,1)\n\n            outputs = model(data)\n            loss = criterion(outputs, label)\n    #       pred = (outputs > 0.5).float()\n    #       lossV += dice_coeff(pred, label).item()\n\n            lossV = dice_loss(outputs, label)\n    #       tot += lossV.item() * data.size(0)\n            valid_loss_total  += loss.item()\n        break\n\n \n    train_loss_total_avg = train_loss_total / len(train_loader)\n    valid_loss_total_avg = 0 #valid_loss_total / len(valid_loader)\n    dice_train = lossL/len(train_loader)\n    dice_valid = 0 #lossV/len(valid_loader)\n    \n    history.append([train_loss_total_avg, valid_loss_total_avg, dice_train, dice_valid]) \n    print('epoch number ', epoch, \"\t\",'Training loss value', train_loss_total_avg , \" \", 'Validation Loss Value', valid_loss_total_avg \\\n         , \" \", 'training dice Value', dice_train, \" \", 'Validation dice Value', dice_valid)\n    \ntorch.save(model.state_dict(), '../working' + '/Unet_Model.pth')   \nhistory = pd.DataFrame(history, columns=['train_loss', 'valid_loss', 'dice_train', 'dice_valid'])  ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## BCE loss and Dice Loss Curves","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(8, 6))\nfor c in ['train_loss', 'valid_loss']:\n    plt.plot(history[c], label=c)\nplt.legend()\nplt.xlabel('Epoch')\nplt.ylabel('BCE Loss')\nplt.title('Training and Validation Losses')\n\nplt.figure(figsize=(8, 6))\nfor c in ['dice_train', 'dice_valid']:\n    plt.plot(history[c], label=c)\nplt.legend()\nplt.xlabel('Epoch')\nplt.ylabel('Dice Loss')\nplt.title('Training and Validation Losses')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib\n\nfile_path = f'../input/prostate-cancer-grade-assessment/train_images/046b35ae95374bfb48cdca8d7c83233f.tiff'\nimage = skimage.io.MultiImage(file_path)[-1]\nimage = cv2.resize(image, (224, 224))\nskimage.io.imsave(\"biopsy.png\", image)\n# image = np.expand_dims(image, axis=1)\nimage = torch.Tensor(image)\nimage = image.unsqueeze(0)\nimage = image.permute(0, 3,2,1)\nimage = image.type(torch.cuda.FloatTensor)\n#             label = label.type(torch.cuda.FloatTensor)\npred = model(image)\n\n\nfile_path = f'../input/prostate-cancer-grade-assessment/train_label_masks/046b35ae95374bfb48cdca8d7c83233f_mask.tiff'\nlabel = skimage.io.MultiImage(file_path)[-1]\nlabel = cv2.resize(label, (224, 224))\nskimage.io.imsave(\"biopsy_label.png\", label)\n\nplt.figure(figsize=(12,12)) \nplt.subplot(1, 3, 1)\ni = cv2.imread('../working/biopsy.png')\nplt.imshow(i)\nplt.subplot(1, 3, 2)\ni = cv2.imread('../working/biopsy_label.png',2)\n# i = i.read_region((0,0), i.level_count - 1, i.level_dimensions[-1])\nplt.imshow(i, cmap = matplotlib.colors.ListedColormap(['black', 'gray', 'green', 'yellow', 'orange', 'red']))\nplt.subplot(1, 3, 3)\npred = pred.permute(0,2,3,1)\nplt.imshow(pred[0].detach().cpu())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"gleason_1 = torch.max(pred)\ntorch.floor(gleason_1)","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}