{"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":"!pip3 install monai","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:20.613198Z","iopub.execute_input":"2021-05-22T08:46:20.613697Z","iopub.status.idle":"2021-05-22T08:46:31.106850Z","shell.execute_reply.started":"2021-05-22T08:46:20.613584Z","shell.execute_reply":"2021-05-22T08:46:31.105763Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport json\nimport csv\nimport random\nimport pickle\nimport cv2\nimport numpy as np\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nimport torchvision.transforms as transforms\n\nfrom PIL import Image, ImageOps, ImageEnhance\nfrom torch.utils.data import Dataset, DataLoader\nfrom scipy.ndimage.measurements import label, center_of_mass\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.metrics import roc_auc_score, roc_curve\n\nimport matplotlib.pyplot as plt\nplt.style.use('ggplot')","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:31.111877Z","iopub.execute_input":"2021-05-22T08:46:31.112212Z","iopub.status.idle":"2021-05-22T08:46:34.317216Z","shell.execute_reply.started":"2021-05-22T08:46:31.112180Z","shell.execute_reply":"2021-05-22T08:46:34.316193Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from monai.transforms import (\n    Activations,\n    AddChanneld,\n    AsDiscrete,\n    Compose,\n    CropForeground,\n    CropForegroundd,\n    LoadImaged,\n    NormalizeIntensityd,\n    RandAffined,\n    RandCropByPosNegLabeld,\n    RandFlipd,\n    Resized,\n    Resize,\n    ScaleIntensityd,\n    SpatialCropd,\n    SpatialCrop,\n    ToTensord, \n    RandRotated,\n    RandAdjustContrastd\n)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:34.318641Z","iopub.execute_input":"2021-05-22T08:46:34.319131Z","iopub.status.idle":"2021-05-22T08:46:35.712050Z","shell.execute_reply.started":"2021-05-22T08:46:34.319051Z","shell.execute_reply":"2021-05-22T08:46:35.711146Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset class","metadata":{}},{"cell_type":"code","source":"class RefugeDataset(Dataset):\n\n    def __init__(self, \n                 root_dir, \n                 find_center_net,\n                 index_path = None,\n                 roi_size=600,\n                 split='train', \n                 data_augm=None\n                ):\n        # Define attributes\n        self.root_dir = root_dir\n        self.split = split\n        if split != 'test':\n            self.transform = Compose(\n                [               \n                    CropForegroundd(keys=[\"img\"], source_key=\"img\"),\n                    Resized(keys=[\"img\"], \n                            spatial_size=[IMG_H, IMG_W], \n                            mode=('bilinear')),\n                ]\n            )\n        else:\n            self.transform = Compose(\n            [               \n                CropForegroundd(keys=[\"img\"], source_key=\"img\"),\n                Resized(keys=[\"img\"], \n                        spatial_size=[IMG_H, IMG_W], \n                        mode=('bilinear')),\n            ]\n        )\n        self.resizer_img = Resize(spatial_size=[RESIZE_W, RESIZE_H], mode=\"bilinear\")\n        self.resizer_seg = Resize(spatial_size=[RESIZE_W, RESIZE_H], mode='nearest')\n\n        self.data_augm = data_augm\n        # Load data index\n        if index_path == None:\n            index_path = os.path.join(self.root_dir, self.split, 'index.json')\n        with open(index_path) as f:\n            #index = json.load(f)\n            #self.index = {'0': index['0'], \n                          #'1': index['1'], \n                          #'2': index['2'], \n                          #'3': index['2'], \n                          #'4': index['4']\n                        #}\n            self.index = json.load(f)\n            \n        self.images = []\n        #self.segs = []\n        if split != 'test':\n            for k in range(len(self.index)):\n                print('Loading {} image {}/{}...'.format(split, k, len(self.index)), end='\\r')\n                img_name = os.path.join(self.root_dir, self.split, 'images', self.index[str(k)]['ImgName'])\n                img = np.array(Image.open(img_name).convert('RGB'))\n                img = transforms.functional.to_tensor(img).numpy()\n                seg_name = os.path.join(self.root_dir, self.split, 'gts', self.index[str(k)]['ImgName'].split('.')[0]+'.bmp')\n                seg = np.array(Image.open(seg_name)).copy()\n                seg = 255. - seg\n                od = (seg>=127.).astype(np.float32)\n                oc = (seg>=250.).astype(np.float32)\n                od = transforms.functional.to_tensor(od).numpy()\n                oc = transforms.functional.to_tensor(oc).numpy()\n\n                data = {'img': img, 'od': od, 'oc': oc}\n                data = self.transform(data)\n                seg = np.concatenate([data['od'], data['oc']], axis=0)\n                #img = data['img']\n                \n                img, _ = center_crop_and_resize(find_center_net, img, seg, \n                                                 roi_size, self.resizer_img, \n                                                 self.resizer_seg)\n                \n                #img = np.array(img)\n                #img = transforms.functional.to_tensor(img).numpy()\n                #img = self.resizer_img(img)\n                self.images.append(img)\n                #self.segs.append(seg)\n        else:\n            for k in range(len(self.index)):\n                print('Loading {} image {}/{}...'.format(split, k, len(self.index)), end='\\r')\n                img_name = os.path.join(self.root_dir, self.split, 'images', self.index[str(k)]['ImgName'])\n                img = np.array(Image.open(img_name).convert('RGB'))\n                img = transforms.functional.to_tensor(img).numpy()\n                data = {'img': img}\n                data = self.transform(data)\n                \n                img, _ = center_crop_and_resize(find_center_net, data['img'], None, \n                                                 roi_size, self.resizer_img, \n                                                 None)\n                #img = data['img']\n                #img = np.moveaxis(img, 0, 2)\n                #img = Image.fromarray(np.uint8(img*255))\n                #img = ImageOps.autocontrast(img, cutoff=0, ignore=0)\n                #img = np.array(img)\n                #img = transforms.functional.to_tensor(img).numpy()\n                #img = self.resizer_img(img)\n                self.images.append(img)\n        print('Succesfully loaded {} dataset.'.format(split) + ' '*50)\n            \n            \n    def __len__(self):\n        return len(self.index)\n\n    def __getitem__(self, idx):\n        # Image\n        img = self.images[idx]\n    \n        # Return only images for 'test' set\n        if self.split == 'test':\n            return torch.Tensor(img)\n        \n        # Else, images and ground truth\n        else:\n            # Label\n            lab = torch.tensor(self.index[str(idx)]['Label'], dtype=torch.float32)\n\n        \n            if self.split == 'train' and self.data_augm != None:\n                data = self.data_augm({'img': img})\n                img = data['img']\n            return torch.Tensor(img), lab\n        ","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.713499Z","iopub.execute_input":"2021-05-22T08:46:35.713923Z","iopub.status.idle":"2021-05-22T08:46:35.739331Z","shell.execute_reply.started":"2021-05-22T08:46:35.713880Z","shell.execute_reply":"2021-05-22T08:46:35.738209Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Metrics","metadata":{}},{"cell_type":"code","source":"EPS = 1e-7\n\ndef compute_dice_coef(input, target):\n    '''\n    Compute dice score metric.\n    '''\n    batch_size = input.shape[0]\n    return sum([dice_coef_sample(input[k,:,:], target[k,:,:]) for k in range(batch_size)])/batch_size\n\ndef dice_coef_sample(input, target):\n    iflat = input.contiguous().view(-1)\n    tflat = target.contiguous().view(-1)\n    intersection = (iflat * tflat).sum()\n    return (2. * intersection) / (iflat.sum() + tflat.sum())\n\n\ndef vertical_diameter(binary_segmentation):\n    '''\n    Get the vertical diameter from a binary segmentation.\n    The vertical diameter is defined as the \"fattest\" area of the binary_segmentation parameter.\n    '''\n\n    # get the sum of the pixels in the vertical axis\n    vertical_axis_diameter = np.sum(binary_segmentation, axis=1)\n\n    # pick the maximum value\n    diameter = np.max(vertical_axis_diameter, axis=1)\n\n    # return it\n    return diameter\n\ndef plot_ROC(classif_preds, classif_gts):\n    fpr, tpr, _ = roc_curve(classif_gts, classif_preds)\n    plt.title('Receiver Operating Characteristic')\n    plt.fill_between(fpr, np.zeros_like(tpr), tpr, alpha=0.2)\n    plt.plot(fpr, tpr)\n    plt.plot([0, 1], ls=\"--\")\n    plt.plot([0, 0], [1, 0] , c=\".7\"), plt.plot([1, 1] , c=\".7\")\n    \n    plt.ylabel('True Positive Rate')\n    plt.xlabel('False Positive Rate')\n    \n    plt.show()\n\ndef vertical_cup_to_disc_ratio(od, oc):\n    '''\n    Compute the vertical cup-to-disc ratio from a given labelling map.\n    '''\n    # compute the cup diameter\n    cup_diameter = vertical_diameter(oc)\n    # compute the disc diameter\n    disc_diameter = vertical_diameter(od)\n\n    return cup_diameter / (disc_diameter + EPS)\n\ndef compute_vCDR_error(pred_od, pred_oc, gt_od, gt_oc):\n    '''\n    Compute vCDR prediction error, along with predicted vCDR and ground truth vCDR.\n    '''\n    pred_vCDR = vertical_cup_to_disc_ratio(pred_od, pred_oc)\n    gt_vCDR = vertical_cup_to_disc_ratio(gt_od, gt_oc)\n    vCDR_err = np.mean(np.abs(gt_vCDR - pred_vCDR))\n    return vCDR_err, pred_vCDR, gt_vCDR\n\n\ndef classif_eval(classif_preds, classif_gts):\n    '''\n    Compute AUC classification score.\n    '''\n    auc = roc_auc_score(classif_gts, classif_preds)\n    return auc\n\n\ndef fov_error(pred_fov, gt_fov):\n    '''\n    Fovea localization error metric (mean root squared error).\n    '''\n    err = np.sqrt(np.sum((gt_fov-pred_fov)**2, axis=1)).mean()\n    return err","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.744141Z","iopub.execute_input":"2021-05-22T08:46:35.744809Z","iopub.status.idle":"2021-05-22T08:46:35.768353Z","shell.execute_reply.started":"2021-05-22T08:46:35.744767Z","shell.execute_reply":"2021-05-22T08:46:35.767062Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Post-processing functions","metadata":{}},{"cell_type":"code","source":"def refine_seg(pred):\n    '''\n    Only retain the biggest connected component of a segmentation map.\n    '''\n    np_pred = pred.numpy()\n        \n    largest_ccs = []\n    for i in range(np_pred.shape[0]):\n        labeled, ncomponents = label(np_pred[i,:,:])\n        bincounts = np.bincount(labeled.flat)[1:]\n        if len(bincounts) == 0:\n            largest_cc = labeled == 0\n        else:\n            largest_cc = labeled == np.argmax(bincounts)+1\n        largest_cc = torch.tensor(largest_cc, dtype=torch.float32)\n        largest_ccs.append(largest_cc)\n    largest_ccs = torch.stack(largest_ccs)\n    \n    return largest_ccs","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.771857Z","iopub.execute_input":"2021-05-22T08:46:35.772410Z","iopub.status.idle":"2021-05-22T08:46:35.787815Z","shell.execute_reply.started":"2021-05-22T08:46:35.772348Z","shell.execute_reply":"2021-05-22T08:46:35.786517Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Network","metadata":{}},{"cell_type":"code","source":"class UNet(nn.Module):\n    def __init__(self, n_channels=3, n_classes=2):\n        super(UNet, self).__init__()\n        self.n_channels = n_channels\n        self.n_classes = n_classes\n        self.epoch = 0\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 \n        self.down4 = Down(512, 1024 // factor)\n        self.up1 = Up(1024, 512 // factor)\n        self.up2 = Up(512, 256 // factor)\n        self.up3 = Up(256, 128 // factor)\n        self.up4 = Up(128, 64)\n        self.output_layer = OutConv(64, n_classes)\n        #self.output_fc = FullyConnect(1024, 1)\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        out = self.up1(x5, x4)\n        out = self.up2(out, x3)\n        out = self.up3(out, x2)\n        out = self.up4(out, x1)\n        out = self.output_layer(out)\n        out = torch.sigmoid(out)\n    \n        return out\n\n    \nclass FullyConnect(nn.Module):\n    \n    def __init__(self, in_channels, out_channels):\n        super().__init__()\n        self.maxpool = nn.AdaptiveMaxPool2d(1)\n        self.fc = nn.Linear(in_channels, out_channels, bias=True)\n    \n    def forward(self, x):\n        x = self.maxpool(x).reshape(x.shape[0], -1)\n        out = self.fc(x)\n        return out\n        \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):\n        super().__init__()\n\n        # Use the normal convolutions to reduce the number of channels\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\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        x = torch.cat([x2, x1], dim=1)\n        return self.conv(x)\n\n\nclass OutConv(nn.Module):\n    '''\n    Simple convolution.\n    '''\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)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.789603Z","iopub.execute_input":"2021-05-22T08:46:35.790238Z","iopub.status.idle":"2021-05-22T08:46:35.820353Z","shell.execute_reply.started":"2021-05-22T08:46:35.790140Z","shell.execute_reply":"2021-05-22T08:46:35.819289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### ResNet50","metadata":{}},{"cell_type":"code","source":"import torchvision.models as models\ndef resent50(pretrained=True,dropout=0.8, freeze=False):\n    resnet = models.resnet50(pretrained=pretrained)\n    if freeze:\n        for child in resnet.children():\n            for param in child.parameters():\n                param.requires_grad = False\n    in_f = resnet.fc.in_features\n    out_f = 1\n    resnet.fc = nn.Sequential(\n          nn.Dropout(dropout),\n          nn.Linear(in_f, out_f),\n          #nn.Softmax()\n        )\n    resnet.epoch = 0\n    return resnet","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.821854Z","iopub.execute_input":"2021-05-22T08:46:35.822388Z","iopub.status.idle":"2021-05-22T08:46:35.842189Z","shell.execute_reply.started":"2021-05-22T08:46:35.822341Z","shell.execute_reply":"2021-05-22T08:46:35.840968Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Resent18","metadata":{}},{"cell_type":"code","source":"import torchvision.models as models\ndef resent18(pretrained=True, dropout=0.8, freeze=False):\n    resnet = models.resnet18(pretrained=pretrained)\n    if freeze:\n        for child in resnet.children():\n            for param in child.parameters():\n                param.requires_grad = False\n    in_f = resnet.fc.in_features\n    out_f = 1\n    resnet.fc = nn.Sequential(\n          nn.Dropout(dropout),\n          nn.Linear(in_f, out_f),\n          #nn.Softmax()\n        )\n    resnet.epoch = 0\n    return resnet","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.843867Z","iopub.execute_input":"2021-05-22T08:46:35.844451Z","iopub.status.idle":"2021-05-22T08:46:35.857012Z","shell.execute_reply.started":"2021-05-22T08:46:35.844403Z","shell.execute_reply":"2021-05-22T08:46:35.855567Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Vgg 13","metadata":{}},{"cell_type":"code","source":"def VGG13(pretrained=True, dropout=0.8, freeze=True, bn=True):\n    if bn:\n        model = models.vgg13_bn(pretrained=pretrained)\n    else:\n        model = models.vgg13(pretrained=pretrained)\n    if freeze:\n        for child in model.features.children():\n            for param in child.parameters():\n                param.requires_grad = False\n    in_f = model.classifier[6].in_features\n    out_f = 1\n    model.classifier[5] = nn.Dropout(dropout)\n    model.classifier[6] = nn.Linear(in_f, out_f)\n    model.epoch = 0\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.858962Z","iopub.execute_input":"2021-05-22T08:46:35.859962Z","iopub.status.idle":"2021-05-22T08:46:35.881837Z","shell.execute_reply.started":"2021-05-22T08:46:35.859872Z","shell.execute_reply":"2021-05-22T08:46:35.879144Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# VGG 11","metadata":{}},{"cell_type":"code","source":"def VGG11(pretrained=True, dropout=0.8, freeze=False, bn=True):\n    if bn:\n        model = models.vgg11_bn(pretrained=pretrained)\n    else:\n        model = models.vgg11(pretrained=pretrained)\n    if freeze:\n        for child in model.features.children():\n            for param in child.parameters():\n                param.requires_grad = False\n    in_f = model.classifier[6].in_features\n    out_f = 1\n    model.classifier[5] = nn.Dropout(dropout)\n    model.classifier[6] = nn.Linear(in_f, out_f)\n    model.epoch = 0\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.884760Z","iopub.execute_input":"2021-05-22T08:46:35.885670Z","iopub.status.idle":"2021-05-22T08:46:35.896376Z","shell.execute_reply.started":"2021-05-22T08:46:35.885624Z","shell.execute_reply":"2021-05-22T08:46:35.895269Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Settings","metadata":{}},{"cell_type":"code","source":"def get_center(model, img, img_resizer):\n    img_res = img_resizer(img)\n    logits = model(torch.Tensor(img_res).unsqueeze(0).to(device))\n    center = find_mass_center((logits[:,0,:,:]>=0.5).type(torch.int8).cpu(), \n                              img.shape[1:3])\n    return center","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.898561Z","iopub.execute_input":"2021-05-22T08:46:35.899284Z","iopub.status.idle":"2021-05-22T08:46:35.909574Z","shell.execute_reply.started":"2021-05-22T08:46:35.899235Z","shell.execute_reply":"2021-05-22T08:46:35.908557Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# img and seg_gt as numpy\ndef center_crop_and_resize(model, img, seg_gt, roi_size, img_resizer, seg_resizer):\n    img_res = img_resizer(img)\n    logits = model(torch.Tensor(img_res).unsqueeze(0).to(device))\n    center = find_mass_center((logits[:,0,:,:]>=0.5).type(torch.int8).cpu(), \n                              img.shape[1:3])\n    \n    cropper = SpatialCrop(roi_center=center, roi_size=roi_size)\n    img = cropper(img)\n    resizer_img = Resize(spatial_size=[256, 259], mode=\"bilinear\")\n    img = resizer_img(img)\n    if seg_resizer != None:\n        seg_gt = cropper(seg_gt)\n        seg_gt = seg_resizer(seg_gt)\n    return img, seg_gt\n\ndef find_mass_center(seg, original_shape):\n    current_shape = seg.shape[1:3]\n    largest_ccs = refine_seg(seg).numpy()\n\n    center = center_of_mass(largest_ccs[0])\n\n    original_center = (center[0] * original_shape[0] / current_shape[0],\n                       center[1] * original_shape[1] / current_shape[1])\n    return original_center\n\n\ndef crop_data(img, center, roi_size):\n    cropped_imgs = torch.zeros([img.shape[0], roi_size, roi_size])\n    cropped_segs = torch.zeros([img.shape[0], roi_size, roi_size])\n    return cropped_imgs","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.912374Z","iopub.execute_input":"2021-05-22T08:46:35.912856Z","iopub.status.idle":"2021-05-22T08:46:35.930104Z","shell.execute_reply.started":"2021-05-22T08:46:35.912811Z","shell.execute_reply":"2021-05-22T08:46:35.928950Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"root_dir = '/kaggle/input/eurecom-aml-2021-challenge-2/refuge_data/refuge_data'\nlr = 2e-5\nbatch_size = 16\nnum_workers = 16\ntotal_epoch = 50","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.932332Z","iopub.execute_input":"2021-05-22T08:46:35.933238Z","iopub.status.idle":"2021-05-22T08:46:35.942630Z","shell.execute_reply.started":"2021-05-22T08:46:35.933175Z","shell.execute_reply":"2021-05-22T08:46:35.941511Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preprocessing transforms","metadata":{}},{"cell_type":"code","source":"ROI_SIZE = 600\nCROP_SIZE = 400\nIMG_W = 1600\nIMG_H = 1600\nRESIZE_W = 256\nRESIZE_H = 256\n\n\n# Data augmentation function, called in dataset.__get_item__\n# Requires keys=['img', 'seg']\n\ntrain_data_augm = Compose(\n            [        \n                RandFlipd(keys=['img' ], prob=0.5, spatial_axis=1),\n                RandFlipd(keys=['img'], prob=0.5, spatial_axis=0),\n                RandRotated(keys=['img'], range_x=[-10, 10], prob=1),\n                RandAdjustContrastd(keys=['img'], gamma=(0.5,1.5), prob=1),\n                ToTensord(keys=['img'])\n            ]\n        )\n","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.944839Z","iopub.execute_input":"2021-05-22T08:46:35.945461Z","iopub.status.idle":"2021-05-22T08:46:35.960351Z","shell.execute_reply.started":"2021-05-22T08:46:35.945346Z","shell.execute_reply":"2021-05-22T08:46:35.958900Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_transform = Compose(\n            [\n                CropForegroundd(keys=[\"img\",\"od\", \"oc\"], source_key=\"img\"),\n                Resized(keys=[\"img\",\"od\", \"oc\"], spatial_size=[IMG_H, IMG_W]),\n                SpatialCropd(keys=[\"img\",\"od\", \"oc\"], roi_center=[IMG_H // 2, CROP_SIZE // 2], roi_size=CROP_SIZE),\n                #Resized(keys=[\"img\",\"od\", \"oc\"], spatial_size=[RESIZE_W, RESIZE_H]),\n                ToTensord(keys=[\"img\",\"od\", \"oc\"]),\n                transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n            ]\n        )\ntest_transform = Compose(\n            [\n                CropForegroundd(keys=[\"img\"], source_key=\"img\"),\n                Resized(keys=[\"img\"], spatial_size=[IMG_H, IMG_W]),\n                SpatialCropd(keys=[\"img\"], roi_center=[IMG_H // 2, CROP_SIZE // 2], roi_size=CROP_SIZE),\n                #Resized(keys=[\"img\"], spatial_size=[RESIZE_W, RESIZE_H]),\n                ToTensord(keys=[\"img\"]),\n                transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n            ])","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:35.962634Z","iopub.execute_input":"2021-05-22T08:46:35.963189Z","iopub.status.idle":"2021-05-22T08:46:35.979377Z","shell.execute_reply.started":"2021-05-22T08:46:35.963145Z","shell.execute_reply":"2021-05-22T08:46:35.978242Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Device, model, loss and optimizer","metadata":{}},{"cell_type":"code","source":"import torch.optim.lr_scheduler as schedulerTorch\n# Device\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n\n# Find center Net\nfind_center_net = UNet(n_channels=3, n_classes=2).to(device)\nfind_center_net.load_state_dict(torch.load('/kaggle/input/unet-pretrained/UNet_base_model.pth'))\n\n\n# Network\n# model = UNet(n_channels=3, n_classes=2).to(device)\nmodel = resent18(dropout=0.75).to(device) #resnet18\n# model = resent18(dropout=0.75, freeze=True).to(device) #resnet18\n# model = resent50(dropout=0.75).to(device) #resnet50\n# model = resent50(dropout=0.75, freeze=True).to(device) #resnet50\n\n# model = VGG11(dropout=0.75, freeze=False).to(device)\n# model = VGG11(dropout=0.75, bn=True, freeze=True).to(device)\n# model = VGG13(dropout=0.75).to(device)\n# model = VGG13(dropout=0.75, freeze=True).to(device)\n# model = VGG13(dropout=0.75, bn=True).to(device)\n# model = VGG13(dropout=0.75, bn=True, freeze=True).to(device)\n# Loss\nseg_loss = torch.nn.BCELoss(reduction='mean')\nclass_loss = torch.nn.BCEWithLogitsLoss()\n# class_loss = nn.NLLLoss()\n\n# Optimizer\noptimizer = optim.Adam(model.parameters(), lr=lr, weight_decay=1e-5)\n\n#Scheduler\n# scheduler = schedulerTorch.ReduceLROnPlateau(optimizer, mode='max', factor=0.5, patience=25)\n# scheduler = schedulerTorch.StepLR(optimizer, 1.0, gamma=0.95)\nscheduler = schedulerTorch.CyclicLR(optimizer, lr, lr*1e-1, cycle_momentum=False, step_size_up=100)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T09:06:44.633815Z","iopub.execute_input":"2021-05-22T09:06:44.634203Z","iopub.status.idle":"2021-05-22T09:06:47.238474Z","shell.execute_reply.started":"2021-05-22T09:06:44.634166Z","shell.execute_reply":"2021-05-22T09:06:47.237113Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create datasets and data loaders\nAll image files are loaded in RAM in order to speed up the pipeline. Therefore, each dataset creation should take a few minutes.","metadata":{}},{"cell_type":"code","source":"# Datasets\ntrain_set = RefugeDataset(root_dir, \n                          split='train',\n                          index_path = '../input/unet-pretrained/balanced_index.json',\n                          find_center_net=find_center_net,\n                          data_augm=train_data_augm,\n                          roi_size=ROI_SIZE)\nval_set = RefugeDataset(root_dir, \n                        split='val',\n                        find_center_net=find_center_net,\n                        roi_size=ROI_SIZE)\ntest_set = RefugeDataset(root_dir, \n                         split='test',\n                         find_center_net=find_center_net,\n                         roi_size=ROI_SIZE)\n\n# Dataloaders\ntrain_loader = DataLoader(train_set, \n                          batch_size=batch_size, \n                          shuffle=True, \n                          num_workers=num_workers,\n                          pin_memory=True,\n                         )\nval_loader = DataLoader(val_set, \n                        batch_size=batch_size, \n                        shuffle=False, \n                        num_workers=num_workers,\n                        pin_memory=True,\n                        )\ntest_loader = DataLoader(test_set, \n                        batch_size=batch_size, \n                        shuffle=False, \n                        num_workers=num_workers,\n                        pin_memory=True)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:46:50.451527Z","iopub.execute_input":"2021-05-22T08:46:50.454385Z","iopub.status.idle":"2021-05-22T08:54:28.591600Z","shell.execute_reply.started":"2021-05-22T08:46:50.454336Z","shell.execute_reply":"2021-05-22T08:54:28.590604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train ResNET50","metadata":{}},{"cell_type":"code","source":"def binary_auc(y_pred, y_test):\n    y_pred_tag = torch.round(torch.sigmoid(y_pred))\n    auc = roc_auc_score(y_test.cpu().numpy(), y_pred.cpu().numpy())    \n    return auc","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:54:28.594153Z","iopub.execute_input":"2021-05-22T08:54:28.594745Z","iopub.status.idle":"2021-05-22T08:54:28.601302Z","shell.execute_reply.started":"2021-05-22T08:54:28.594702Z","shell.execute_reply":"2021-05-22T08:54:28.600395Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def getLogit(tensore):\n    zeri = torch.ones_like(tensore) - tensore\n    return torch.stack([zeri, tensore]).T","metadata":{"execution":{"iopub.status.busy":"2021-05-22T08:54:28.603121Z","iopub.execute_input":"2021-05-22T08:54:28.603734Z","iopub.status.idle":"2021-05-22T08:54:28.617545Z","shell.execute_reply.started":"2021-05-22T08:54:28.603691Z","shell.execute_reply":"2021-05-22T08:54:28.616417Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define parameters\nnb_train_batches = len(train_loader)\nnb_val_batches = len(val_loader)\nnb_iter = 0\nbest_val_acc = 0.\n\nwhile model.epoch < total_epoch:\n    # Accumulators\n\n    train_classif_gts, val_classif_gts = [], []\n    train_loss, val_loss = 0., 0.\n    train_acc, val_acc = 0., 0.\n    train_pred, train_log = [], []\n    val_pred, val_log = [], []\n    ############\n    # TRAINING #\n    ############\n    model.train()\n    train_data = iter(train_loader)\n    for k in range(nb_train_batches):\n        # Loads data\n        imgs, classif_gts = train_data.next()\n        imgs, classif_gts  = imgs.to(device), classif_gts.to(device)\n        \n        # Forward pass\n        logits = model(imgs)[:,0]\n\n        loss = class_loss(logits, classif_gts )\n    \n        # Backward pass\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        \n        train_loss += loss.item() / nb_train_batches\n        train_pred.append(logits.detach())\n        train_log.append(classif_gts)\n        # Increase iterations\n        nb_iter += 1\n        \n        # Std out\n        print('Epoch {}, iter {}/{}, loss {:.6f}'.format(model.epoch+1, k+1, nb_train_batches, loss.item()) + ' '*20, \n              end='\\r')\n\n    train_acc = binary_auc(torch.cat(train_pred,dim=0), torch.cat(train_log,dim=0))\n    ##############\n    # VALIDATION #\n    ##############\n    model.eval()\n    val_predictions = []\n    with torch.no_grad():\n        val_data = iter(val_loader)\n        for k in range(nb_val_batches):\n            # Loads data\n            imgs, classif_gts = val_data.next()\n            imgs, classif_gts = imgs.to(device), classif_gts.to(device)\n\n            # Forward pass\n            logits = model(imgs)\n            val_predictions += logits.cpu()\n            val_loss += class_loss(logits[:,0], classif_gts).item() / nb_val_batches\n            val_pred.append(logits[:,0].detach())\n            val_log.append(classif_gts)\n  \n            # Std out\n            print('Validation iter {}/{}'.format(k+1, nb_val_batches) + ' '*50, \n                  end='\\r')\n    val_classif_preds = torch.sigmoid(torch.from_numpy(np.concatenate(val_predictions)))\n    #val_acc = binary_auc(torch.ones_like(torch.cat(val_pred,dim=0)), torch.cat(val_log,dim=0))\n    val_acc = binary_auc(torch.cat(val_pred,dim=0), torch.cat(val_log,dim=0))\n    #scheduler.step(val_acc)\n    over05 = (val_classif_preds > 0.5).sum()\n    \n    # Validation results\n    print('VALIDATION epoch {} - LR: {}'.format(model.epoch+1, optimizer.param_groups[0]['lr'])+' '*50)\n    print('LOSSES: {:.4f} (train), {:.4f} (val)'.format(train_loss, val_loss))\n    print('Classification (ACC): {:.4f} (train), {:.4f} (val) - Over 0.5 {:3} (val)'.format(train_acc, val_acc, over05))\n    scheduler.step()\n    # Save model if best validation AUC is reached\n    if val_acc > best_val_acc and model.epoch > 3:\n        torch.save(model.state_dict(), '/kaggle/working/best_ACC_weights.pth')\n        best_val_acc = val_acc\n        print('Best validation AUC reached. Saved model weights and classifier.---------------------')\n        plot_ROC(torch.cat(val_pred,dim=0).cpu(), torch.cat(val_log,dim=0).cpu())\n        plt.show()\n        plt.hist(val_classif_preds.numpy())\n        plt.show()\n    print('_'*50)\n    if model.epoch % 4 == 0:\n        plot_ROC(torch.cat(val_pred,dim=0).cpu(), torch.cat(val_log,dim=0).cpu())\n        \n    # End of epoch\n    model.epoch += 1\n        \n","metadata":{"execution":{"iopub.status.busy":"2021-05-22T09:11:06.589068Z","iopub.execute_input":"2021-05-22T09:11:06.589555Z","iopub.status.idle":"2021-05-22T09:21:04.389944Z","shell.execute_reply.started":"2021-05-22T09:11:06.589521Z","shell.execute_reply":"2021-05-22T09:21:04.388413Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load best model + classifier","metadata":{}},{"cell_type":"code","source":"# Load model and classifier\nmodel = VGG11(pretrained=False).to(device)\n# model = resent18(False).to(device)\nmodel.load_state_dict(torch.load('/kaggle/working/best_ACC_weights.pth'))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Predictions on test set","metadata":{}},{"cell_type":"code","source":"\nnb_test_batches = len(test_loader)\nmodel.eval()\ntest_vCDRs = []\nwith torch.no_grad():\n    test_data = iter(test_loader)\n    for k in range(nb_test_batches):\n        # Loads data\n        imgs = test_data.next()\n        imgs = imgs.to(device)\n\n        # Forward pass\n        logits = model(imgs)\n        # Std out\n        print('Test iter {}/{}'.format(k+1, nb_test_batches) + ' '*50, \n              end='\\r')\n            \n\n        # Compute and store vCDRs\n        \n        test_vCDRs += logits.cpu()\n\n    # Glaucoma predictions from vCDRs\n    test_classif_preds = torch.sigmoid(torch.from_numpy(np.concatenate(test_vCDRs)))\n    \n# Prepare and save .csv file\ndef create_submission_csv(prediction, submission_filename='/kaggle/working/submission.csv'):\n    \"\"\"Create a sumbission file in the appropriate format for evaluation.\n\n    :param\n    prediction: list of predictions (ex: [0.12720, 0.89289, ..., 0.29829])\n    \"\"\"\n    \n    with open(submission_filename, mode='w') as csv_file:\n        fieldnames = ['Id', 'Predicted']\n        writer = csv.DictWriter(csv_file, fieldnames=fieldnames)\n        writer.writeheader()\n\n        for i, p in enumerate(prediction):\n            writer.writerow({'Id': \"T{:04d}\".format(i+1), 'Predicted': '{:f}'.format(p)})\n\ncreate_submission_csv(test_classif_preds)\n\n# The submission.csv file is under /kaggle/working/submission.csv.\n# If you want to submit it, you should download it before closing the current kernel.","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!head /kaggle/working/submission.csv","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import IPython.display as ipd\nbeep = np.sin(2*np.pi*400*np.arange(10000*2)/10000)\nipd.Audio(beep, rate=10000, autoplay=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Merge","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\n\n\nfile1 = pd.read_csv(\"submission_mino.csv\", index_col=0)\n# file3 = pd.read_csv(\"submission_18_9999_9382.csv\", index_col=0)\nfile2 = pd.read_csv(\"submission_vgg_1_9521.csv\", index_col=0)\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"merged = file1.merge(file2, right_index=True, left_index=True,)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"file1[\"Predicted\"] = merged.filter(regex=\"Predicted*\").mean(axis=1)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"file1.to_csv(\"submission_merge.csv\")","metadata":{},"execution_count":null,"outputs":[]}]}