{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport torch\nfrom torch.utils.data import DataLoader, Dataset, BatchSampler\nimport os\nimport matplotlib.pyplot as plt\nfrom PIL import Image","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Let's load up the csv and see what we got"},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/aptos2019-blindness-detection/train.csv')\ndf.sample(5)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.isna().sum()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Simple class labels. Nothing is missing. Now, let's check out the images"},{"metadata":{"trusted":true},"cell_type":"code","source":"class eyeData(Dataset):\n    def __init__(self,imageDir,csv,transform=None):\n        super(eyeData,self).__init__()\n        self.dataDirectory = imageDir\n        self.tabular = pd.read_csv(csv)\n        self.transform = transform\n        _, _, files = next(os.walk(self.dataDirectory))\n        self.filenames = files\n        \n    def __len__(self):\n        return len(self.filenames)\n    \n    def __getitem__(self,idx):\n        row = self.tabular.iloc[idx].values\n        diag = row[1]\n        img_name = row[0]\n        img_path = os.path.join(self.dataDirectory,img_name+'.png')\n        img = Image.open(img_path)\n        \n        getted = {\"image\":img,\"diagnosis\":torch.LongTensor([diag]).unsqueeze(1)}\n        if self.transform:\n            getted[\"image\"] = self.transform(getted[\"image\"])\n        \n        return getted\n        \nEDAdata = eyeData(imageDir='/kaggle/input/aptos2019-blindness-detection/train_images/',\n               csv='/kaggle/input/aptos2019-blindness-detection/train.csv')\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test = EDAdata[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plotImgwithDiag(obs):\n    plt.imshow(obs[\"image\"])\n    plt.title(\" Diagnosis: {}\".format(int(obs[\"diagnosis\"])))\n    \nplotImgwithDiag(test)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def collateDict(batch):\n    collated = {}\n    for idx,obs in enumerate(batch):\n        collated[\"BatchIndex_\"+str(idx)]=obs\n        \n    return collated","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Yup, all that so we can load the images in parallel and view them"},{"metadata":{"trusted":true},"cell_type":"code","source":"dataIterator = DataLoader(EDAdata,batch_size=4,shuffle=True,num_workers=4,collate_fn=collateDict)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for j,batch in enumerate(dataIterator):\n    plt.figure(figsize=(20,10))\n    for idx,I in enumerate(batch.values()):\n        plt.subplot(1,4,idx+1)\n        plotImgwithDiag(I)\n    plt.show()\n    if j==2:\n        break","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## So the images are of different sizes. Let's check out the distribution of classes too"},{"metadata":{"trusted":true},"cell_type":"code","source":"df.groupby([\"diagnosis\"]).count()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Your standard disease scenario, but I wouldn't treat it as an outlier detection, so we'll just stick to a classification for our baseline modelling efforts.\n## Let's start with a Resnet backbone with just a softmax regression"},{"metadata":{"trusted":true},"cell_type":"code","source":"from torchvision.models import resnet34\n\nvgg = resnet34(pretrained=False)\nvgg.load_state_dict(torch.load('/kaggle/input/resnet34/resnet34.pth'))\n\nfor param in vgg.parameters():\n    para.requires_grad = False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class VGGEyeClassifier(torch.nn.Module):\n    def __init__(self,dropoutRate=0.5):\n        super(VGGEyeClassifier,self).__init__()\n        self.size = 8\n        self.features = torch.nn.Sequential(vgg.conv1,\n                                            vgg.bn1,\n                                            vgg.relu,\n                                            vgg.maxpool,\n                                            vgg.layer1,\n                                            vgg.layer2,\n                                            vgg.layer3,\n                                            vgg.layer4,\n                                            torch.nn.AdaptiveAvgPool2d(output_size=(self.size,\n                                                                                    self.size)))\n        self.classifier = torch.nn.Sequential(\n            torch.nn.Dropout2d(dropoutRate),\n            torch.nn.BatchNorm2d(512),\n            torch.nn.Conv2d(\n                in_channels=512,\n                out_channels=256,\n                kernel_size=self.size,\n                stride=1,\n                padding=0),\n            torch.nn.ReLU(),\n            torch.nn.BatchNorm2d(256),\n            torch.nn.Dropout2d(dropoutRate),\n            torch.nn.Conv2d(\n                in_channels=256,\n                out_channels=128,\n                kernel_size=1,\n                stride=1,\n                padding=0),\n            torch.nn.ReLU(),\n            torch.nn.BatchNorm2d(128),\n            torch.nn.Dropout2d(dropoutRate),\n            torch.nn.Conv2d(\n                in_channels=128,\n                out_channels=5,\n                kernel_size=1,\n                stride=1,\n                padding=0))\n    \n    def forward(self,x):\n        x = self.features(x)\n        x = self.classifier(x)\n        return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"theNet = VGGEyeClassifier(dropoutRate=0.2).cuda()\ntest = theNet(torch.randn(5,3,256,256).cuda())\nprint(test.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"## Now let's define a couple of transformations for the data coming in"},{"metadata":{"trusted":true},"cell_type":"code","source":"from torchvision.transforms import functional as F\nfrom torchvision import transforms as T\nfrom torch.utils.data import SubsetRandomSampler\nfrom random import uniform","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"## there's only 3662 images total. Instead of trying to pass in batches and have them be the same size, I'm just going to train this baby one observation at a time but with a boatload of transforms"},{"metadata":{"trusted":true},"cell_type":"code","source":"class RandomBrightness(object):\n    def __init__(self,rng=(0.75,1.25)):\n        self.rng = rng\n    def __call__(self,img):\n        rand = uniform(self.rng[0],\n                         self.rng[1])\n        return F.adjust_brightness(img,rand)\n    \nclass RandomContrast(object):\n    def __init__(self,rng=(0.75,1.25)):\n        self.rng = rng\n    def __call__(self,img):\n        rand = uniform(self.rng[0],\n                         self.rng[1])\n        return F.adjust_contrast(img,rand)\n\nclass RandomGamma(object):\n    def __init__(self,rng=(0.75,1.25)):\n        self.rng = rng\n    def __call__(self,img):\n        rand = uniform(self.rng[0],\n                         self.rng[1])\n        return F.adjust_gamma(img,rand)\n    \nclass RandomHue(object):\n    def __init__(self,rng=(-0.15,0.15)):\n        self.rng = rng\n    def __call__(self,img):\n        rand = uniform(self.rng[0],\n                         self.rng[1])\n        return F.adjust_hue(img,rand)\n    \nclass RandomSat(object):\n    def __init__(self,rng=(0.75,1.25)):\n        self.rng = rng\n    def __call__(self,img):\n        rand = uniform(self.rng[0],\n                         self.rng[1])\n        return F.adjust_saturation(img,rand)\n    \nTrainData = eyeData(imageDir='/kaggle/input/aptos2019-blindness-detection/train_images/',\n                    csv='/kaggle/input/aptos2019-blindness-detection/train.csv',\n                    transform=T.Compose([T.Resize((256,256)),\n                                         T.RandomApply([T.RandomApply([T.RandomAffine(degrees=359,\n                                                                        translate=(0.2,0.2),\n                                                                        shear=(20,20,20,20)),\n                                                        T.RandomHorizontalFlip(1),\n                                                        T.RandomVerticalFlip(1)],p=0.7),\n                                         T.RandomApply([RandomBrightness(),\n                                                        RandomContrast(),\n                                                        RandomGamma(),\n                                                        RandomSat()],p=0.5)],p=0.7),\n                                         T.ToTensor()]))\n\n\n\n\n# data loader will start loading up several batches into memory so my GPU keeps working\ndataIteratorTrain = DataLoader(TrainData,\n                               batch_size=1,\n                               num_workers=4,\n                               shuffle=True)\n\n \nprint(len(dataIteratorTrain))\nfor j,batch in enumerate(dataIteratorTrain):\n    \n    print(batch[\"image\"].shape)\n    \n    if j>5:\n        break","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Let's see what our transformations look like. Let's define a quick function to look at them"},{"metadata":{"trusted":true},"cell_type":"code","source":"def LookAtImage(image):\n    npImage = torch.squeeze(image).detach().cpu().numpy().transpose((1,2,0))\n    plt.figure(figsize=(10,10))\n    plt.imshow(npImage)\n    \nfor j,batch in enumerate(dataIteratorTrain):\n    LookAtImage(batch[\"image\"])\n    plt.title(\"Diagnosis\"+str(batch[\"diagnosis\"].detach().numpy()))\n    plt.show()\n    if j>5:\n        break","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Good stuff. So all the data transformations work. Now it's time for gradient descent."},{"metadata":{"trusted":true},"cell_type":"code","source":"import time","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"LR = 1e-3\nepochs = 20\ntheNet = VGGEyeClassifier(0.5).cuda()\ndataIteratorTrain = DataLoader(TrainData,\n                               batch_size=2,\n                               num_workers=2,\n                               shuffle=True)\nlossFunc = torch.nn.CrossEntropyLoss()\noptim = torch.optim.Adam(filter(lambda x: x.requires_grad,theNet.parameters()),\n                         lr=LR)\n\ndef passThroughTrain():\n    start = time.time()\n    print(' ')\n    sumLosses = torch.cuda.FloatTensor([0])\n    for idx,batch in enumerate(dataIteratorTrain):\n        image = batch[\"image\"].cuda()\n        diag = batch[\"diagnosis\"].cuda()\n        optim.zero_grad()\n        pred = theNet(image)\n        loss = lossFunc(pred,diag)\n        loss.backward()\n        optim.step()\n        sumLosses += loss.detach()\n        print(\"Batch {}/{}\".\n              format((idx+1),(len(dataIteratorTrain))),end='\\r')\n    print(\"Mean Training Loss: {}\".format(sumLosses.detach().cpu().numpy()/len(dataIteratorTrain)))\n    print(\"Epoch time: {}\".format(time.time()-start))\n    return sumLosses.detach().cpu().numpy()/len(dataIteratorTrain)\n\n\nTrainingLosses = []\nprint(\"Beginning training for {} epochs\".format(epochs))\nfor i in range(epochs):\n    print(\"Epoch\"+str(i+1))\n    TrainingLosses.append(passThroughTrain())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"#### torch.save(theNet.state_dict(),'VGGEyeClassifier')"},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(TrainingLosses)","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":1}