{"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":"markdown","source":"#  Glaucoma Detection using ConvNets","metadata":{}},{"cell_type":"markdown","source":"***Table of Contents:***\n1. Introduction\n2. Data Vizualisation and Exploration\n3. Image Preprocessing\n4. Data Augmentation, dealing with Class Imbalance\n5. Training for Segmentation\n6. Training for Classification\n7. Conclusion","metadata":{}},{"cell_type":"markdown","source":"# Introduction","metadata":{}},{"cell_type":"markdown","source":"Glaucoma is a prevalent condition related to an abnormal fluid balance in the eye that causes an increase of internal ocular pressure. The increase of pressure gradually damages the eye optic nerve. If undiagnosed, these damages can result in permanent vision loss. Approximately 2.86% of the global population over 40 years old is affected by glaucoma [1]. Patients affected by glaucoma usually do not present symptoms in the early stages of the disease, while an early diagnosis is critical to prevent irreversible damages. It is thus important to develop inexpensive detection methods, in order to massively and systematically control patients, before the symptoms appear.\n\nOne way to diagnose glaucoma is to perform a visual examination of the inside back surface of the eye (fundus). The images are obtained by special cameras through a dilated pupil. The main advantage of this technique, called \"Retinal Fundus Imaging\", is to be brief (usually a minute long) and painless to the patient, making it suited for simple routine checks. However, establishing an accurate diagnosis from these images is particularly difficult. This task is currently performed by human experts, which represents a significant financial burden. Therefore, automatic glaucoma detection methods from fundus imaging are both highly desirable and challenging.\n\nOur goal in this challenge is to contribute to the detection of Glaucoma using Image segmentation. \n","metadata":{}},{"cell_type":"markdown","source":"# Imports","metadata":{}},{"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\nfrom torch.utils.data import Dataset, DataLoader\nfrom scipy.ndimage.measurements import label\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.metrics import roc_auc_score, roc_curve\nimport matplotlib.pyplot as plt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# NB !!!!!! DON'T RUN THE NEXT CELL","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nscore_1={'Technique':['Baseline','Crop and Saturation','CLAHE','Balancing the data','adding sata for both classes'],'Resize':[1,1,1,1,1],'Crop':[0,1,1,0,0],'Adjust_saturation':[0,1,1,0,1],'Rescale':[0,1,0,0,0],'Data_Aug':[None,None,None,'train set size : 800',\"train_set size: 1160\"],'AUC_score':[0.9350,0.912535,0.669826,0.9432,0.913125]}\nscores=pd.DataFrame(score_1,index=None)\nscores.to_csv('/kaggle/working/scores.csv')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"scores.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"root_dir = '/kaggle/input/eurecom-aml-2021-challenge-2/refuge_data/refuge_data'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def training_images(root_dir):\n    images = []\n    path=root_dir+'/train/images'\n    for file in os.listdir(path):\n        if file.endswith(\".jpg\"):\n            images.append(file)\n    return images\ndef val_images(root_dir):\n    images = []\n    path=root_dir+'/val/images'\n    for file in os.listdir(path):\n        if file.endswith(\".jpg\"):\n            images.append(file)\n    return images\ndef test_images(root_dir):\n    images = []\n    path=root_dir+'/test/images'\n    for file in os.listdir(path):\n        if file.endswith(\".jpg\"):\n            images.append(file)\n    return images","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_idx=training_images(root_dir)\nval_idx=val_images(root_dir)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Visualization","metadata":{}},{"cell_type":"markdown","source":"Here's a preview of the images:","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(25, 16))\n\nfor i in range(10):\n    name=random.choice(train_idx)\n    ax = fig.add_subplot(5, 5,  i+1, xticks=[], yticks=[])\n    path=root_dir+'/train/images/'+name\n    image = cv2.imread(path)\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    image = cv2.resize(image, (256, 256))\n\n    plt.imshow(image)\n    ax.set_title('Sample :'+name)\n        ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"To better visualize the area where the segmentation is to be performed, let's apply CLAHE ( we'll talk about it later)","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(25, 16))\n\nfor i in range(10):\n    name=random.choice(train_idx)\n    ax = fig.add_subplot(5, 5,  i+1, xticks=[], yticks=[])\n    path=root_dir+'/train/images/'+name\n    image = cv2.imread(path)\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    img2 = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))\n    img2 = clahe.apply(img2)\n    image = cv2.resize(img2, (256, 256))\n\n    plt.imshow(image)\n    ax.set_title('Sample :'+name)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now that of the extracted segmented masks:","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(25, 16))\n\nfor i in range(10):\n    name=random.choice(train_idx)\n    ax = fig.add_subplot(5, 5,  i+1, xticks=[], yticks=[])\n    name=name.replace('jpg','bmp')\n    path=root_dir+'/train/gts/'+name\n    image = Image.open(path).convert('RGB')\n    #image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    #image = cv2.resize(image, (256, 256))\n\n    plt.imshow(image)\n    ax.set_title('Sample :'+name)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now let's visualize class distribution for each set","metadata":{}},{"cell_type":"code","source":"#these cells should be run after defining the train_set, Val_set and Test_set","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_non_gl=[k for k in range(400) if train_set.index[str(k)]['Label']==0]\ntrain_gl=[k for k in range(400) if train_set.index[str(k)]['Label']==1]\nval_non_gl=[k for k in range(400) if val_set.index[str(k)]['Label']==0]\nval_gl=[k for k in range(400) if val_set.index[str(k)]['Label']==1]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#this cell should be run after defining the train_set, Val_set and Test_set\nglaucoma = [len(train_non_gl),len(val_non_gl)]\nnon_glaucoma = [len(train_gl),len(val_gl)]\nbarWidth = 0.4\n\nr1 = range(len(glaucoma))\nr2 = [x + barWidth for x in r1]\n\nplt.bar(r1, glaucoma, width = barWidth, color = ['gray' for i in glaucoma])\nplt.bar(r2, non_glaucoma, width = barWidth, color = ['pink' for i in y1])\nplt.xticks([r + barWidth / 2 for r in range(len(glaucoma))], ['train set', 'validation set'])\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Preprocessing","metadata":{}},{"cell_type":"markdown","source":"***Motivation:***\n\n***Image-based classification can be very challenging because  it depends on the available set of images, their resolution, the data and features to be extracted from the images …\nThis is why an image processing is extremely important. However, there exists a lot of techniques in this domain.\nWe decided to compare the results of different technique in the first part of our work.***\n","metadata":{}},{"cell_type":"markdown","source":"Different techniques:\n1. Baseline Model : Reshaping images to (256,256)\n2. Cropping+Adjusting Saturation\n3. CLAHE","metadata":{}},{"cell_type":"markdown","source":"We use the following cell to visualize different data preprocessing techniques:","metadata":{}},{"cell_type":"code","source":"#CLAHEgreenfunction : inspired from https://www.kaggle.com/virajbagal/aptos-clahe-efficiennetb5\ndef CLAHEgreen(image_name):\n    image=cv2.imread(image_name)\n    green=image[:, :, 1]\n    clipLimit = 2.0\n    tileGridSize = (8,8)\n    clahe=cv2.createCLAHE(clipLimit = clipLimit, tileGridSize = tileGridSize)\n    cla=clahe.apply(green)\n#     cla=clahe.apply(cla)\n    img=cv2.merge((cla,cla,cla))\n\n    return img","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport cv2\n\n\nroot_dir = '/kaggle/input/eurecom-aml-2021-challenge-2/refuge_data/refuge_data'\nimg = mpimg.imread(root_dir+'/train/images/g0006.jpg')\nimgplot = plt.imshow(img)\nplt.title('Original Image')\nplt.show()\n\nimg2=Image.open(root_dir+'/train/images/g0006.jpg').convert('RGB')\nimg2=transforms.functional.adjust_saturation(img2, 2)\nimg2=transforms.functional.crop(img2, 500, 0, 1000, 1000)\nprint(np.array(img2).shape)\nimgplot = plt.imshow(img2)\nplt.title('Cropped image, with adjusted saturation')\nplt.show()\n\n# create a CLAHE object (Arguments are optional).\nimg2=cv2.imread(root_dir+'/train/images/g0006.jpg')\nimg2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)\nclahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))\nimg2 = clahe.apply(img2)\nprint(img2.shape)\nimgplot = plt.imshow(img2)\nplt.title('CLAHE Image')\nplt.show()\n\ny=500\nx=0\nh=1000\nw=1000\n\ncrop = img2[y:y+h, x:x+w]\nimg2 = cv2.cvtColor(crop, cv2.COLOR_GRAY2BGR)\nprint(img2.shape)\nimgplot = plt.imshow(img2)\nplt.title('CLAHE Image cropped')\nplt.show()\n\nimg2=cv2.imread(root_dir+'/train/images/g0006.jpg')\nimg=CLAHEgreen(root_dir+'/train/images/g0006.jpg')\nimgplot = plt.imshow(img)\nplt.title('CLAHE on green only Image')\nprint(img.shape)\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preprocessing","metadata":{}},{"cell_type":"code","source":"#preprocessing for technique number 2 : Resize(256x256)+Crop+adjust Saturation\ndef preprocess_img(img):\n    img=transforms.functional.adjust_saturation(img, 2)\n    img=transforms.functional.crop(img, 500, 0, 1000, 1000)\n    \n    \ndef preprocess_seg(seg):\n    seg=transforms.functional.crop(seg, 500, 0, 1000, 1000)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#preprocessing for technique number 4 : CLAHE+cropping+resize(256x265)\ndef preprocess_img_CLAHE(img_name):\n    img2=cv2.imread(img_name)\n    img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)\n    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))\n    img2 = clahe.apply(img2)\n\n    y=500\n    x=0\n    h=1000\n    w=1000\n    crop = img2[y:y+h, x:x+w]\n    return(crop)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def CLAHE2(img_name):\n    img=CLAHEgreen(img_name)\n    y=500\n    x=0\n    h=1000\n    w=1000\n    crop = img[y:y+h, x:x+w]\n    return(crop)\n    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset class","metadata":{}},{"cell_type":"code","source":"#to run for technique 1 and 2\nclass RefugeDataset(Dataset):\n\n    def __init__(self, root_dir, split='train', output_size=(256,256)):\n        # Define attributes\n        self.output_size = output_size\n        self.root_dir = root_dir\n        self.split = split\n        \n        # Load data index\n        with open(os.path.join(self.root_dir, self.split, 'index.json')) as f:\n            self.index = json.load(f)\n            \n        self.images = []\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=Image.open(img_name).convert('RGB')\n            ##preprocessing the images\n            #preprocess_img(img)\n            ###preprocessing the images\n            img = np.array(img)\n\n            img = transforms.functional.to_tensor(img)\n            img = transforms.functional.resize(img, self.output_size, interpolation=Image.BILINEAR)\n#            img=transforms.functional.normalize(img,(0.5, 0.5,0.5), (0.5, 0.5,0.5))\n            self.images.append(img)\n            \n        # Load ground truth for 'train' and 'val' sets\n        if split != 'test':\n            self.segs = []\n            for k in range(len(self.index)):\n                print('Loading {} segmentation {}/{}...'.format(split, k, len(self.index)), end='\\r')\n                seg_name = os.path.join(self.root_dir, self.split, 'gts', self.index[str(k)]['ImgName'].split('.')[0]+'.bmp')\n                seg=Image.open(seg_name)\n                ###preprocessing the segmented images\n                #preprocess_seg(seg)\n                ###preprocessing the segmented images\n                seg = np.array(seg).copy()\n                seg = 255. - seg\n                od = (seg>=127.).astype(np.float32)\n                oc = (seg>=250.).astype(np.float32)\n                od = torch.from_numpy(od[None,:,:])\n                oc = torch.from_numpy(oc[None,:,:])\n                \n                od = transforms.functional.resize(od, self.output_size, interpolation=Image.NEAREST)\n                oc = transforms.functional.resize(oc, self.output_size, interpolation=Image.NEAREST)\n                seg = torch.cat([od, oc], dim=0)\n #               seg=transforms.functional.normalize(seg,(0.5, 0.5), (0.5, 0.5))\n                self.segs.append(seg)\n                \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 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            # Segmentation masks\n            seg = self.segs[idx]\n\n            # Fovea localization\n            f_x = self.index[str(idx)]['Fovea_X']\n            f_y = self.index[str(idx)]['Fovea_Y']\n            fov = torch.FloatTensor([f_x, f_y])\n        \n            return img, lab, seg, fov, self.index[str(idx)]['ImgName']","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#for technique number 3 and 4  : CLAHE with/without Cropping\nclass RefugeDataset(Dataset):\n\n    def __init__(self, root_dir, split='train', output_size=(256,256)):\n        # Define attributes\n        self.output_size = output_size\n        self.root_dir = root_dir\n        self.split = split\n        \n        # Load data index\n        with open(os.path.join(self.root_dir, self.split, 'index.json')) as f:\n            self.index = json.load(f)\n            \n        self.images = []\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            ##preprocessing the images\n            img=CLAHE2(img_name)\n            ###preprocessing the images\n\n            img = transforms.functional.to_tensor(img)\n            img = transforms.functional.resize(img, self.output_size, interpolation=Image.BILINEAR)\n\n            self.images.append(img)\n            \n        # Load ground truth for 'train' and 'val' sets\n        if split != 'test':\n            self.segs = []\n            for k in range(len(self.index)):\n                print('Loading {} segmentation {}/{}...'.format(split, k, len(self.index)), end='\\r')\n                seg_name = os.path.join(self.root_dir, self.split, 'gts', self.index[str(k)]['ImgName'].split('.')[0]+'.bmp')\n                seg=Image.open(seg_name)\n                ###preprocessing the segmented images\n                preprocess_seg(seg)\n                ###preprocessing the segmented images\n                seg = np.array(seg).copy()\n                seg = 255. - seg\n                od = (seg>=127.).astype(np.float32)\n                oc = (seg>=250.).astype(np.float32)\n                od = torch.from_numpy(od[None,:,:])\n                oc = torch.from_numpy(oc[None,:,:])\n                \n                od = transforms.functional.resize(od, self.output_size, interpolation=Image.NEAREST)\n                oc = transforms.functional.resize(oc, self.output_size, interpolation=Image.NEAREST)\n                seg = torch.cat([od, oc], dim=0)\n #               seg=transforms.functional.normalize(seg,(0.5, 0.5), (0.5, 0.5))\n                self.segs.append(seg)\n                \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 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            # Segmentation masks\n            seg = self.segs[idx]\n\n            # Fovea localization\n            f_x = self.index[str(idx)]['Fovea_X']\n            f_y = self.index[str(idx)]['Fovea_Y']\n            fov = torch.FloatTensor([f_x, f_y])\n        \n            return img, lab, seg, fov, self.index[str(idx)]['ImgName']","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#to run in order to fill the scores table to compare the models\ntechniqueID='Baseline'\ncr=0\nsat=0\nsc=0\nda=\"None\"","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Augmentation:","metadata":{}},{"cell_type":"markdown","source":"Our dataset has two big issues:\n\n**-Very small dataset:** 400 samples to train is very little, we need to increase this size.\n\n**-Imbalanced data:** you can see in the figures above  the class distribution for every set, before and after data augmentation.\n\n**Proposed Solution:** Adding samples to train_set.index by slightly rotating the original image, or simply reshaping them.\n","metadata":{}},{"cell_type":"code","source":"def update(index,k,l):\n    st=index[str(k)]\n    st['ImgName']=\"r\"+str(l)+st['ImgName']\n    index[str(len(index))]=st\n    return(index)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import random\ndef generate_images(train_set,root_dir):\n    for k,i in enumerate(train_idx):\n        image_path = root_dir+'/train/images/'+i\n        j=i.replace(\"jpg\",\"bmp\")\n        mask_path = root_dir+'/train/gts/'+j\n        image = Image.open(image_path)\n\n        if train_set.index[str(k)]['Label']==1:\n            for l in range(10):\n                b=random.randint(-20,20)\n                image = image.convert('RGB')\n                img = transforms.functional.rotate(image,b)\n                \n                \n                \n                img=np.array(img)\n                img = transforms.functional.to_tensor(img)\n                \n                img = transforms.functional.resize(img, (256,256), interpolation=Image.BILINEAR)\n                msk = Image.open(mask_path)\n                msk = transforms.functional.rotate(msk,b,fill=255)\n                seg = np.array(msk)\n                seg = 255. - seg\n                od = (seg>=127.).astype(np.float32)\n                oc = (seg>=250.).astype(np.float32)\n                od = torch.from_numpy(od[None,:,:])\n                oc = torch.from_numpy(oc[None,:,:])\n                od = transforms.functional.resize(od, (256,256), interpolation=Image.NEAREST)\n                oc = transforms.functional.resize(oc, (256,256), interpolation=Image.NEAREST)\n                seg = torch.cat([od, oc], dim=0)\n                train_set.images.append(img)\n                train_set.segs.append(seg)\n                #update the index\n                train_set.index=update(train_set.index,k,l)\n        if train_set.index[str(k)]['Label']==0:\n            b=random.randint(-20,20)\n            image = image.convert('RGB')\n            img = transforms.functional.rotate(image,b)\n                \n                \n                \n            img=np.array(img)\n            img = transforms.functional.to_tensor(img)\n                \n            img = transforms.functional.resize(img, (256,256), interpolation=Image.BILINEAR)\n            msk = Image.open(mask_path)\n            msk = transforms.functional.rotate(msk,b,fill=255)\n            seg = np.array(msk)\n            seg = 255. - seg\n            od = (seg>=127.).astype(np.float32)\n            oc = (seg>=250.).astype(np.float32)\n            od = torch.from_numpy(od[None,:,:])\n            oc = torch.from_numpy(oc[None,:,:])\n            od = transforms.functional.resize(od, (256,256), interpolation=Image.NEAREST)\n            oc = transforms.functional.resize(oc, (256,256), interpolation=Image.NEAREST)\n            seg = torch.cat([od, oc], dim=0)\n            train_set.images.append(img)\n            train_set.segs.append(seg)\n                #update the index\n            l=0\n            train_set.index=update(train_set.index,k,l)","metadata":{"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\n\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":{"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":{"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\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        return out\n\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":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Settings","metadata":{}},{"cell_type":"code","source":"root_dir = '/kaggle/input/eurecom-aml-2021-challenge-2/refuge_data/refuge_data'\nlr = 1e-4\nbatch_size = 8\nnum_workers = 8\ntotal_epoch = 100","metadata":{"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')\nval_set = RefugeDataset(root_dir, \n                        split='val')\ntest_set = RefugeDataset(root_dir, \n                         split='test')\n\n# Dataloaders\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"***In case of data augmentation:***","metadata":{}},{"cell_type":"code","source":"generate_images(train_set,root_dir)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(train_set)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_loader = DataLoader(train_set, \n                          batch_size=8, \n                          shuffle=True, \n                          num_workers=8,\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":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Device, model, loss and optimizer","metadata":{}},{"cell_type":"code","source":"# Device\ndevice = torch.device(\"cuda:0\")\n\n# Network\nmodel = UNet(n_channels=3, n_classes=2).to(device)\n\n# Loss\nseg_loss = torch.nn.BCELoss(reduction='mean')\n\n# Optimizer\noptimizer = optim.Adam(model.parameters(), lr=lr)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train for OC/OD segmentation","metadata":{}},{"cell_type":"code","source":"# Define parameters\nnb_train_batches = len(train_loader)\nnb_val_batches = len(val_loader)\nnb_iter = 0\nbest_val_auc = 0.\n\nwhile model.epoch < total_epoch:\n    # Accumulators\n    train_vCDRs, val_vCDRs = [], []\n    train_classif_gts, val_classif_gts = [], []\n    train_loss, val_loss = 0., 0.\n    train_dsc_od, val_dsc_od = 0., 0.\n    train_dsc_oc, val_dsc_oc = 0., 0.\n    train_vCDR_error, val_vCDR_error = 0., 0.\n    \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, seg_gts, fov_coords, names = train_data.next()\n        imgs, classif_gts, seg_gts = imgs.to(device), classif_gts.to(device), seg_gts.to(device)\n\n        # Forward pass\n        logits = model(imgs)\n        loss = seg_loss(logits, seg_gts)\n \n        # Backward pass\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        train_loss += loss.item() / nb_train_batches\n        \n        with torch.no_grad():\n            # Compute segmentation metric\n            pred_od = refine_seg((logits[:,0,:,:]>=0.5).type(torch.int8).cpu()).to(device)\n            pred_oc = refine_seg((logits[:,1,:,:]>=0.5).type(torch.int8).cpu()).to(device)\n            gt_od = seg_gts[:,0,:,:].type(torch.int8)\n            gt_oc = seg_gts[:,1,:,:].type(torch.int8)\n            dsc_od = compute_dice_coef(pred_od, gt_od)\n            dsc_oc = compute_dice_coef(pred_oc, gt_oc)\n            train_dsc_od += dsc_od.item()/nb_train_batches\n            train_dsc_oc += dsc_oc.item()/nb_train_batches\n\n\n            # Compute and store vCDRs\n            vCDR_error, pred_vCDR, gt_vCDR = compute_vCDR_error(pred_od.cpu().numpy(), pred_oc.cpu().numpy(), gt_od.cpu().numpy(), gt_oc.cpu().numpy())\n            train_vCDRs += pred_vCDR.tolist()\n            train_vCDR_error += vCDR_error / nb_train_batches\n            train_classif_gts += classif_gts.cpu().numpy().tolist()\n            \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 a logistic regression on vCDRs\n    train_vCDRs = np.array(train_vCDRs).reshape(-1,1)\n    train_classif_gts = np.array(train_classif_gts)\n    clf = LogisticRegression(random_state=0, solver='lbfgs').fit(train_vCDRs, train_classif_gts)\n    train_classif_preds = clf.predict_proba(train_vCDRs)[:,1]\n    train_auc = classif_eval(train_classif_preds, train_classif_gts)\n    \n    ##############\n    # VALIDATION #\n    ##############\n    model.eval()\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, seg_gts, fov_coords, names = val_data.next()\n            imgs, classif_gts, seg_gts = imgs.to(device), classif_gts.to(device), seg_gts.to(device)\n\n            # Forward pass\n            logits = model(imgs)\n            val_loss += seg_loss(logits, seg_gts).item() / nb_val_batches\n\n            # Std out\n            print('Validation iter {}/{}'.format(k+1, nb_val_batches) + ' '*50, \n                  end='\\r')\n            \n            # Compute segmentation metric\n            pred_od = refine_seg((logits[:,0,:,:]>=0.5).type(torch.int8).cpu()).to(device)\n            pred_oc = refine_seg((logits[:,1,:,:]>=0.5).type(torch.int8).cpu()).to(device)\n            gt_od = seg_gts[:,0,:,:].type(torch.int8)\n            gt_oc = seg_gts[:,1,:,:].type(torch.int8)\n            dsc_od = compute_dice_coef(pred_od, gt_od)\n            dsc_oc = compute_dice_coef(pred_oc, gt_oc)\n            val_dsc_od += dsc_od.item()/nb_val_batches\n            val_dsc_oc += dsc_oc.item()/nb_val_batches\n            \n            # Compute and store vCDRs\n            vCDR_error, pred_vCDR, gt_vCDR = compute_vCDR_error(pred_od.cpu().numpy(), pred_oc.cpu().numpy(), gt_od.cpu().numpy(), gt_oc.cpu().numpy())\n            val_vCDRs += pred_vCDR.tolist()\n            val_vCDR_error += vCDR_error / nb_val_batches\n            val_classif_gts += classif_gts.cpu().numpy().tolist()\n            \n\n    # Glaucoma predictions from vCDRs\n    val_vCDRs = np.array(val_vCDRs).reshape(-1,1)\n    val_classif_gts = np.array(val_classif_gts)\n    val_classif_preds = clf.predict_proba(val_vCDRs)[:,1]\n    val_auc = classif_eval(val_classif_preds, val_classif_gts)\n        \n    # Validation results\n    print('VALIDATION epoch {}'.format(model.epoch+1)+' '*50)\n    print('LOSSES: {:.4f} (train), {:.4f} (val)'.format(train_loss, val_loss))\n    print('OD segmentation (Dice Score): {:.4f} (train), {:.4f} (val)'.format(train_dsc_od, val_dsc_od))\n    print('OC segmentation (Dice Score): {:.4f} (train), {:.4f} (val)'.format(train_dsc_oc, val_dsc_oc))\n    print('vCDR error: {:.4f} (train), {:.4f} (val)'.format(train_vCDR_error, val_vCDR_error))\n    print('Classification (AUC): {:.4f} (train), {:.4f} (val)'.format(train_auc, val_auc))\n    \n    # Save model if best validation AUC is reached\n    if val_auc > best_val_auc:\n        torch.save(model.state_dict(), '/kaggle/working/best_AUC_weights.pth')\n        with open('/kaggle/working/best_AUC_classifier.pkl', 'wb') as clf_file:\n            pickle.dump(clf, clf_file)\n        best_val_auc = val_auc\n        print('Best validation AUC reached. Saved model weights and classifier.')\n    print('_'*50)\n        \n    # End of epoch\n    model.epoch += 1\n        \n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load best model + classifier","metadata":{}},{"cell_type":"code","source":"# Load model and classifier\nmodel = UNet(n_channels=3, n_classes=2).to(device)\nmodel.load_state_dict(torch.load('/kaggle/working/best_AUC_weights.pth'))\nwith open('/kaggle/working/best_AUC_classifier.pkl', 'rb') as clf_file:\n    clf = pickle.load(clf_file)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Check performance is maintained on validation","metadata":{}},{"cell_type":"code","source":"model.eval()\nval_vCDRs = []\nval_classif_gts = []\nval_loss = 0.\nval_dsc_od = 0.\nval_dsc_oc = 0.\nval_vCDR_error = 0.\nwith torch.no_grad():\n    val_data = iter(val_loader)\n    for k in range(nb_val_batches):\n        # Loads data\n        imgs, classif_gts, seg_gts, fov_coords, names = val_data.next()\n        imgs, classif_gts, seg_gts = imgs.to(device), classif_gts.to(device), seg_gts.to(device)\n\n        # Forward pass\n        logits = model(imgs)\n        val_loss += seg_loss(logits, seg_gts).item() / nb_val_batches\n\n        # Std out\n        print('Validation iter {}/{}'.format(k+1, nb_val_batches) + ' '*50, \n              end='\\r')\n\n        # Compute segmentation metric\n        pred_od = refine_seg((logits[:,0,:,:]>=0.5).type(torch.int8).cpu()).to(device)\n        pred_oc = refine_seg((logits[:,1,:,:]>=0.5).type(torch.int8).cpu()).to(device)\n        gt_od = seg_gts[:,0,:,:].type(torch.int8)\n        gt_oc = seg_gts[:,1,:,:].type(torch.int8)\n        dsc_od = compute_dice_coef(pred_od, gt_od)\n        dsc_oc = compute_dice_coef(pred_oc, gt_oc)\n        val_dsc_od += dsc_od.item()/nb_val_batches\n        val_dsc_oc += dsc_oc.item()/nb_val_batches\n\n        # Compute and store vCDRs\n        vCDR_error, pred_vCDR, gt_vCDR = compute_vCDR_error(pred_od.cpu().numpy(), pred_oc.cpu().numpy(), gt_od.cpu().numpy(), gt_oc.cpu().numpy())\n        val_vCDRs += pred_vCDR.tolist()\n        val_vCDR_error += vCDR_error / nb_val_batches\n        val_classif_gts += classif_gts.cpu().numpy().tolist()\n\n\n# Glaucoma predictions from vCDRs\nval_vCDRs = np.array(val_vCDRs).reshape(-1,1)\nval_classif_gts = np.array(val_classif_gts)\nval_classif_preds = clf.predict_proba(val_vCDRs)[:,1]\nval_auc = classif_eval(val_classif_preds, val_classif_gts)\n\n# Validation results\nprint('VALIDATION '+' '*50)\nprint('LOSSES: {:.4f} (val)'.format(val_loss))\nprint('OD segmentation (Dice Score): {:.4f} (val)'.format(val_dsc_od))\nprint('OC segmentation (Dice Score): {:.4f} (val)'.format(val_dsc_oc))\nprint('vCDR error: {:.4f} (val)'.format(val_vCDR_error))\nprint('Classification (AUC): {:.4f} (val)'.format(val_auc))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"### Add score to csv file:\nscores=pd.read_csv('/kaggle/working/scores.csv')\n\n\nscores.head()\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"scores=scores.drop(['Unnamed: 0'],axis=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#score={'Technique':techniqueID,'Resize':[1],'Crop':cr,'Adjust_saturation':sat,'Rescale':sc,'Data_Aug':da,'AUC_score':[val_auc]}\nscores.loc[len(scores.index)] = [techniqueID, 1, cr,sat,sc,da,val_auc] \n\nscores.to_csv('/kaggle/working/scores.csv')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Direct Classification using CNN models : A Comparative Analysis","metadata":{}},{"cell_type":"markdown","source":"In this section, we wanted to try out different CNN models and compare their output. The models predict directly the class of every sample without going through OC/OD segmentation.","metadata":{}},{"cell_type":"markdown","source":"# DEFINING THE TRAINING AND THE VALIDATION SETS:","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nX_train=pd.DataFrame({'ImageName':train_idx,'Class':[str(train_set.index[str(k)]['Label']) for k in range(400)]})\nX_train.describe()\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train['Class']=np.array(X_train['Class']).reshape(-1,1)\nX_val['Class']=np.array(X_val['Class']).reshape(-1,1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_val=pd.DataFrame({'ImageName':val_idx,'Class':[str(val_set.index[str(k)]['Label']) for k in range(400)]})\nX_val.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 1. VGG16","metadata":{}},{"cell_type":"code","source":"from keras.applications.vgg16 import VGG16, preprocess_input\nfrom keras import layers\nfrom keras.models import Model, Sequential\nfrom keras.optimizers import Adam, RMSprop\nfrom keras.callbacks import EarlyStopping\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.utils import Sequence","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"base_model = VGG16(\n    weights=\"imagenet\",\n    include_top=False, \n    input_shape=(224,224) + (3,)\n)\n\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_datagen = ImageDataGenerator(\n    rotation_range=15,\n    width_shift_range=0.1,\n    height_shift_range=0.1,\n    shear_range=0.1,\n    brightness_range=[0.5, 1.5],\n    horizontal_flip=True,\n    vertical_flip=True,\n    preprocessing_function=preprocess_input\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.applications.vgg16 import preprocess_input\ntrain_path=root_dir+'/train/images/'\nval_path=root_dir+'/val/images/'\ntrain_generator=train_datagen.flow_from_dataframe(dataframe=X_train,directory=train_path, x_col='ImageName',y_col='Class',class_mode='binary',batch_size=8,\n                                            target_size=(224,224))\n\nvalidation_generator=train_datagen.flow_from_dataframe(dataframe=X_val,directory=val_path,x_col='ImageName',y_col='Class',class_mode='binary',batch_size=8,\n                                               target_size=(224,224))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"NUM_CLASSES = 1\n\nmodel = Sequential()\nmodel.add(base_model)\nmodel.add(layers.Flatten())\nmodel.add(layers.Dropout(0.5))\nmodel.add(layers.Dense(NUM_CLASSES, activation='sigmoid'))\n\nmodel.layers[0].trainable = False\n\nmodel.compile(\n    loss='binary_crossentropy',\n    optimizer=RMSprop(lr=1e-4),\n    metrics=['accuracy','AUC']\n)\n\n    \nmodel.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"EPOCHS = 30\n#es = EarlyStopping(\n#    monitor='val_auc', \n #   mode='max',\n  #  patience=6\n#\n\nhistory = model.fit_generator(\n    train_generator,\n    steps_per_epoch=50,\n    epochs=EPOCHS,\n    validation_data=validation_generator,\n    validation_steps=25)\n#,\n   # callbacks=[es]\n#","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history['accuracy'])\nplt.plot(history.history['val_accuracy'])\nplt.title('model accuracy')\nplt.ylabel('accuracy')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history['auc'])\nplt.plot(history.history['val_auc'])\nplt.title('model auc')\nplt.ylabel('auc')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nval_classif_predsVGG = model.predict(validation_generator)\n\nval_aucVGG = classif_eval(val_classif_predsVGG, X_train['Class'])\nprint(val_aucVGG)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"***CONCLUSION***\n\nAs you can see, the VGG16 gives a validation accuracy of 0.5039 and and AUC score of 0.6683.","metadata":{}},{"cell_type":"markdown","source":"# ResNet50","metadata":{}},{"cell_type":"code","source":"pip install git+https://github.com/qubvel/classification_models.git","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from classification_models.keras import Classifiers\nResNet50, preprocess_input = Classifiers.get('resnet50')\nmodelResNet50 = ResNet50((256,256, 3), weights='imagenet')\n\nfor layer in modelResNet50.layers[:]:\n    layer.trainable = False\n    \nmodelRes = Sequential()\nmodelRes.add(modelResNet50)\nmodelRes.add(layers.Flatten())\nmodelRes.add(layers.Dense(1024, activation='relu'))\nmodelRes.add(layers.Dense(1, activation='sigmoid'))\n\n\nmodelRes.compile(loss='binary_crossentropy', optimizer=optimizers.Adam(lr=1e-5),metrics=[\"accuracy\"])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"modelRes.compile(\n    loss='binary_crossentropy',\n    optimizer=RMSprop(lr=1e-4),\n    metrics=['accuracy','AUC'])\n\nhistory = modelRes.fit_generator(\n    train_generator,\n    steps_per_epoch=50,\n    epochs=EPOCHS,\n    validation_data=validation_generator,\n    validation_steps=25)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history['accuracy'])\nplt.plot(history.history['val_accuracy'])\nplt.title('model accuracy')\nplt.ylabel('accuracy')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history['auc'])\nplt.plot(history.history['val_auc'])\nplt.title('model auc')\nplt.ylabel('auc')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# LeNet","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.layers import Conv2D , Dense,MaxPooling2D,Flatten,GlobalAveragePooling2D\nfrom tensorflow.keras.models import Sequential\nLeNet = Sequential([\n    Conv2D(6, (2, 2), activation='relu', input_shape=(224,224, 3)),\n    MaxPooling2D(),\n    Conv2D(16, (2, 2),activation='relu'),\n    MaxPooling2D(),\n    Conv2D(16, (2, 2),activation='relu'),\n    MaxPooling2D(),\n    Flatten(),\n    Dense(250, activation='relu'),\n    Dense(100, activation='relu'),\n    Dense(1,activation='softmax')\n])\n\n\nopt=tf.keras.optimizers.Adam()\n\nLeNet.compile(optimizer=opt, \n              loss='categorical_crossentropy', \n              metrics=['accuracy','AUC'])\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"LeNet.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = LeNet.fit_generator(\n    train_generator,\n    steps_per_epoch=50,\n    epochs=EPOCHS,\n    validation_data=validation_generator,\n    validation_steps=25)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history['accuracy'])\nplt.plot(history.history['val_accuracy'])\nplt.title('model accuracy')\nplt.ylabel('accuracy')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history.history['auc']","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history['auc'])\nplt.plot(history.history['val_auc'])\nplt.title('model auc')\nplt.ylabel('auc')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Predictions on test set","metadata":{}},{"cell_type":"code","source":"nb_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\n        # Std out\n        print('Test iter {}/{}'.format(k+1, nb_test_batches) + ' '*50, \n              end='\\r')\n            \n        # Compute segmentation\n        pred_od = refine_seg((logits[:,0,:,:]>=0.5).type(torch.int8).cpu()).to(device)\n        pred_oc = refine_seg((logits[:,1,:,:]>=0.5).type(torch.int8).cpu()).to(device)\n            \n        # Compute and store vCDRs\n        pred_vCDR = vertical_cup_to_disc_ratio(pred_od.cpu().numpy(), pred_oc.cpu().numpy())\n        test_vCDRs += pred_vCDR.tolist()\n            \n\n    # Glaucoma predictions from vCDRs\n    test_vCDRs = np.array(test_vCDRs).reshape(-1,1)\n    test_classif_preds = clf.predict_proba(test_vCDRs)[:,1]\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":[]}]}