{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"!pip install jovian --upgrade","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport torch\nimport pandas as pd\nimport numpy as np\nfrom torch.utils.data import Dataset, random_split, DataLoader\nfrom PIL import Image\nimport torchvision.models as models\nimport matplotlib.pyplot as plt\nfrom tqdm.notebook import tqdm\nimport torchvision.transforms as T\nimport sklearn.metrics as m\nimport torch.nn.functional as F\nimport torch.nn as nn\nfrom torchvision.utils import make_grid\nfrom sklearn.model_selection import train_test_split\nimport jovian\nfrom torchvision.datasets import ImageFolder\n\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"project_name = 'Course Project - Blindness Detection'\ndirectory = '../input/aptos2019-blindness-detection'\n\ntrain_trans = T.Compose([\n#     T.RandomCrop(512, padding=8, padding_mode='reflect'),\n    T.RandomResizedCrop(256, scale=(0.5,0.9), ratio=(1, 1)), \n#    T.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.1),\n#     T.RandomHorizontalFlip(), \n#     T.RandomRotation(10),\n    T.Resize([256,256]),\n    T.ToTensor(), \n#     T.Normalize(*imagenet_stats,inplace=True), \n#     T.RandomErasing(inplace=True)\n])\n\nvalid_trans = T.Compose([\n    T.Resize([256,256]),\n    T.ToTensor()\n])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_labels = pd.read_csv(directory + '/train.csv' )\nlabels = {0 : 'No DR',1 : 'Mild', 2 : 'Moderate',3 : 'Severe',4 : 'Proliferative DR'}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.imshow(train_trans(Image.open(directory + '/train_images/' + train_labels.id_code.loc[0] + '.png')).permute(1,2,0))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(10):\n    print(train_trans(Image.open(directory + '/train_images/' + train_labels.id_code.loc[i] + '.png')).shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_labels.diagnosis.hist()\nplt.xticks([0,1,2,3,4])\nplt.grid(False)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def encode_label(label):\n    target = torch.zeros(5)\n    for l in str(label).split(' '):\n        target[int(l)] = 1.\n    return target\nclass Blindness(Dataset):\n    def __init__(self, df, root_dir, transform=None):\n        self.df = df\n        self.transform = transform\n        self.root_dir = root_dir\n        \n    def __len__(self):\n        return len(self.df)    \n    \n    def __getitem__(self, idx):\n        row = self.df.loc[idx]\n        img_id, img_label = row['id_code'], row['diagnosis']\n        img_fname = self.root_dir + \"/\" + img_id + \".png\"\n        img = Image.open(img_fname)\n        if self.transform:\n            img = self.transform(img)\n        return img,encode_label(img_label)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_labels.diagnosis.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"np.random.seed(40)\ncols = ['id_code','diagnosis']\ntrain_len = np.random.randn(len(train_labels)) < 0.75\nt_ds,test_ds = train_labels[train_len].reset_index(),train_labels[~train_len].reset_index()\nt_ds, test_ds = t_ds[cols],test_ds[cols]\n\nnp.random.seed(40)\nval_len = np.random.rand(len(t_ds)) < 0.8\ntrain_ds,valid_ds = t_ds[val_len].reset_index(),t_ds[~val_len].reset_index()\ntrain_ds,valid_ds = train_ds[cols],valid_ds[cols]\n\n\nprint(\"train : {}\\ntest : {}\\ntrain_split : {}\\nvalid_split : {}\\n{}\".format(t_ds.shape[0],test_ds.shape[0],train_ds.shape[0],valid_ds.shape[0], t_ds.shape[0] == (train_ds.shape[0] + valid_ds.shape[0])))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_transformed = Blindness(train_ds,directory + '/train_images', transform = train_trans)\nvalid_transformed = Blindness(valid_ds,directory + '/train_images', transform = valid_trans)\ntest_transformed = Blindness(test_ds,directory + '/train_images', transform = train_trans)\n\nbatch_size = 5\ntrain_dl = DataLoader(train_transformed,batch_size,shuffle = True, num_workers = 4, pin_memory = True)\nvalid_dl = DataLoader(valid_transformed,batch_size * 2,num_workers = 4, pin_memory = True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def batch_display(x_dl):\n    for i,j in x_dl:\n        fig,ax = plt.subplots(figsize = (20,10))\n        ax.imshow(make_grid(i,nrow = 10).permute(1,2,0))\n        break\nbatch_display(train_dl)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def F_score(output, label, threshold=0.5, beta=1):\n    prob = output > threshold\n    label = label > threshold\n\n    TP = (prob & label).sum(1).float()\n    TN = ((~prob) & (~label)).sum(1).float()\n    FP = (prob & (~label)).sum(1).float()\n    FN = ((~prob) & label).sum(1).float()\n\n    precision = torch.mean(TP / (TP + FP + 1e-12))\n    recall = torch.mean(TP / (TP + FN + 1e-12))\n    F2 = (1 + beta**2) * precision * recall / (beta**2 * precision + recall + 1e-12)\n    return F2.mean(0)\n\nclass ImageClassificationBase(nn.Module):\n    def training_step(self, batch):\n        images, labels = batch \n        out = self(images)                  # Generate predictions\n        loss = F.binary_cross_entropy(out, labels) # Calculate loss\n        return loss\n    \n    def validation_step(self, batch):\n        images, labels = batch \n        out = self(images)                    # Generate predictions\n        loss = F.binary_cross_entropy(out, labels)   # Calculate loss\n        acc = F_score(out, labels)           # Calculate accuracy\n        return {'val_loss': loss.detach(), 'val_acc': acc}\n        \n    def validation_epoch_end(self, outputs):\n        batch_losses = [x['val_loss'] for x in outputs]\n        epoch_loss = torch.stack(batch_losses).mean()   # Combine losses\n        batch_accs = [x['val_acc'] for x in outputs]\n        epoch_acc = torch.stack(batch_accs).mean()      # Combine accuracies\n        return {'val_loss': epoch_loss.item(), 'val_acc': epoch_acc.item()}\n    \n    def epoch_end(self, epoch, result):\n        print(\"Epoch [{}], train_loss: {:.4f}, val_loss: {:.4f}, val_acc: {:.4f}\".format(\n            epoch, result['train_loss'], result['val_loss'], result['val_acc']))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class Blindness(ImageClassificationBase):\n    def __init__(self):\n        super().__init__()\n        self.network = models.resnet50(pretrained = True)\n        f = self.network.fc.in_features\n        self.network.fc = nn.Linear(f,5)\n#         self.network = nn.Sequential(\n#                         nn.Conv2d(3,32,kernel_size = 3, padding = 1), #32 * 256 * 256\n#                         nn.ReLU(),\n#                         nn.Conv2d(32,64,kernel_size = 3, padding = 1), #64 * 256 * 256\n#                         nn.ReLU(),\n#                         nn.MaxPool2d(2,2), #64 * 128 * 128\n                        \n# #                         nn.Conv2d(64,128,kernel_size = 3, padding = 1), #128 * 128 * 128\n# #                         nn.ReLU(),\n# #                         nn.Conv2d(128,256,kernel_size = 3, padding = 1), #256 * 128 * 128\n# #                         nn.ReLU(),\n# #                         nn.MaxPool2d(2,2), #256 * 64* 64\n            \n# #                         nn.Conv2d(256,512,kernel_size = 3, padding = 1), #512 * 64 *64 \n# #                         nn.ReLU(),\n# #                         nn.Conv2d(512,512,kernel_size = 3, padding = 1), #512 * 64 *64 \n# #                         nn.ReLU(),\n# #                         nn.MaxPool2d(2,2), #512 * 32 *32 \n                        \n# #                         nn.Conv2d(512,512,kernel_size = 3, padding = 1), #512 * 32 *32 \n# #                         nn.ReLU(),\n# #                         nn.Conv2d(512,1024,kernel_size = 3, padding = 1), #1024 * 32 *32 \n# #                         nn.ReLU(),\n# #                         nn.MaxPool2d(2,2), #1024 * 16 * 16\n                        \n# #                         nn.Conv2d(1024,1024,kernel_size = 3, padding = 1), #1024 * 16 * 16\n# #                         nn.ReLU(),\n# #                         nn.Conv2d(1024,1024,kernel_size = 3, padding = 1), #1024 * 16 * 16\n# #                         nn.ReLU(),\n# #                         nn.MaxPool2d(2,2), #1024 * 8 * 8\n            \n#                         nn.Flatten(),\n#                         nn.Linear(64*32*32,1024),\n#                         nn.Linear(1024,512),\n#                         nn.Linear(512,5)\n#         )\n    def forward(self,xb):\n        return torch.sigmoid(self.network(xb))\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = Blindness()\ntorch.cuda.empty_cache()\nmodel","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for images, labels in train_dl:\n    print('images.shape:', images.shape)\n    out = model(images)\n    print('out.shape:', out.shape)\n    print('out[0]:', out[0])\n    break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"F.binary_cross_entropy(out[0],labels[0])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_default_device():\n    \"\"\"Pick GPU if available, else CPU\"\"\"\n    if torch.cuda.is_available():\n        return torch.device('cuda')\n    else:\n        return torch.device('cpu')\n    \ndef to_device(data, device):\n    \"\"\"Move tensor(s) to chosen device\"\"\"\n    if isinstance(data, (list,tuple)):\n        return [to_device(x, device) for x in data]\n    return data.to(device, non_blocking=True)\n\nclass DeviceDataLoader():\n    \"\"\"Wrap a dataloader to move data to a device\"\"\"\n    def __init__(self, dl, device):\n        self.dl = dl\n        self.device = device\n        \n    def __iter__(self):\n        \"\"\"Yield a batch of data after moving it to device\"\"\"\n        for b in self.dl: \n            yield to_device(b, self.device)\n\n    def __len__(self):\n        \"\"\"Number of batches\"\"\"\n        return len(self.dl)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = get_default_device()\ndevice","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dl = DeviceDataLoader(train_dl, device)\nval_dl = DeviceDataLoader(valid_dl, device)\nto_device(model, device);","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"@torch.no_grad()\ndef evaluate(model, val_loader):\n    model.eval()\n    outputs = [model.validation_step(batch) for batch in val_loader]\n    return model.validation_epoch_end(outputs)\n\ndef fit(epochs, lr, model, train_loader, val_loader, opt_func=torch.optim.SGD):\n    history = []\n    optimizer = opt_func(model.parameters(), lr)\n    for epoch in range(epochs):\n        # Training Phase \n        model.train()\n        train_losses = []\n        for batch in tqdm(train_loader):\n            loss = model.training_step(batch)\n            train_losses.append(loss)\n            loss.backward()\n            optimizer.step()\n            optimizer.zero_grad()\n        # Validation phase\n        result = evaluate(model, val_loader)\n        result['train_loss'] = torch.stack(train_losses).mean().item()\n        model.epoch_end(epoch, result)\n        history.append(result)\n    return history","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = to_device(Blindness(), device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"evaluate(model,val_dl)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"num_epochs = 10\nopt_func = torch.optim.Adam\nlr = 0.001","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = fit(num_epochs,lr,model, train_dl, val_dl, opt_func)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"jovian.log_metrics(train_loss=history[-1]['train_loss'], \n                   val_loss=history[-1]['val_loss'], \n                   val_acc=history[-1]['val_acc'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_accuracies(history):\n    accuracies = [x['val_acc'] for x in history]\n    plt.plot(accuracies, '-x')\n    plt.xlabel('epoch')\n    plt.ylabel('accuracy')\n    plt.title('Accuracy vs. No. of epochs');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_accuracies(history)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_losses(history):\n    train_losses = [x.get('train_loss') for x in history]\n    val_losses = [x['val_loss'] for x in history]\n    plt.plot(train_losses, '-bx')\n    plt.plot(val_losses, '-rx')\n    plt.xlabel('epoch')\n    plt.ylabel('loss')\n    plt.legend(['Training', 'Validation'])\n    plt.title('Loss vs. No. of epochs');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_losses(history)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def decode_target(target, text_labels=False, threshold=0.5):\n    result = []\n    for i, x in enumerate(target):\n        if (x >= threshold):\n            if text_labels:\n                result.append(labels[i] + \"(\" + str(i) + \")\")\n            else:\n                result.append(str(i))\n    return ' '.join(result)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def predict_image(img, model):\n    # Convert to a batch of 1\n    xb = to_device(img.unsqueeze(0), device)\n    # Get predictions from model\n    yb = model(xb)\n    # Pick index with highest probability\n    _, preds  = torch.max(yb, dim=1)\n    # Retrieve the class label\n    return labels[preds[0].item()]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img, label = test_transformed[0]\nplt.imshow(img.permute(1, 2, 0))\nprint('Label:', label ,', Predicted:', predict_image(img, model))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img, label = test_transformed[120]\nplt.imshow(img.permute(1, 2, 0))\nprint('Label:', label,', Predicted:', predict_image(img, model))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_loader = DeviceDataLoader(DataLoader(test_transformed, batch_size*2), device)\nresult = evaluate(model, test_loader)\nresult","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"jovian.log_metrics(test_loss=result['val_loss'], test_acc=result['val_acc'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"@torch.no_grad()\ndef predict_dl(dl, model):\n    torch.cuda.empty_cache()\n    batch_probs = []\n    for xb, _ in tqdm(dl):\n        probs = model(xb)\n        batch_probs.append(probs.cpu().detach())\n    batch_probs = torch.cat(batch_probs)\n    return [decode_target(x) for x in batch_probs]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_preds = predict_dl(test_loader, model)\nsubmission_df = pd.read_csv(directory + '/test.csv') \nsubmission_df.Label = test_preds","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_fname = 'submission.csv'\nsubmission_df.to_csv(sub_fname, index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"jovian.commit(project = project_name)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}