{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport torchvision\nimport torch.nn as nn\nfrom tqdm import tqdm\nfrom PIL import Image, ImageFile\nfrom torch.utils.data import Dataset\nimport torch\nfrom torchvision import transforms\nimport os\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport collections.abc\nfrom collections import OrderedDict\nfrom sklearn.model_selection import train_test_split\nimport re\nimport math\nfrom typing import Optional\nimport torch.nn.init as init\nfrom inspect import isfunction\n\ndevice = torch.device(\"cuda:0\")\nImageFile.LOAD_TRUNCATED_IMAGES = True\nepochs = 15","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from albumentations import (\n    HorizontalFlip, IAAPerspective, ShiftScaleRotate, CLAHE, RandomRotate90,\n    Transpose, ShiftScaleRotate, Blur, OpticalDistortion, GridDistortion, HueSaturationValue,\n    IAAAdditiveGaussianNoise, GaussNoise, MotionBlur, MedianBlur, IAAPiecewiseAffine,\n    IAASharpen, IAAEmboss, RandomContrast, RandomBrightness, Flip, OneOf, Compose, RandomGamma, \n    ElasticTransform, ChannelShuffle,RGBShift, Rotate\n)","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"class RetinopathyDatasetTest(Dataset):\n    def __init__(self, data,mode = 'test'):\n        #self.data = pd.read_csv(csv_file)\n        self.mode = mode\n        self.data = data.reset_index()\n        self.img_dir = '../input/aptos2019-blindness-detection/test_images' if mode == 'test' else '../input/aptos2019-blindness-detection/train_images' \n        _,_,_,self.transform = data_transforms('center') \n        \n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        img_name = os.path.join(self.img_dir, self.data.loc[idx, 'id_code'] + '.png')\n        image = Image.open(img_name)\n        image = image.resize((320, 320), resample=Image.BILINEAR)\n        image = self.transform(image)\n        if self.mode == 'test':\n            return {'image': transforms.ToTensor()(image)}\n        else:\n            return {'image': transforms.ToTensor()(image),'label': self.data.loc[idx,'diagnosis']}","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"First, let's try to visualize how the images look like within test/training set."},{"metadata":{"trusted":true},"cell_type":"code","source":"\nfor i,path in enumerate(os.listdir('../input/aptos2019-blindness-detection/test_images')):\n    img_path = os.path.join('../input/aptos2019-blindness-detection/test_images',path)\n    im = Image.open(img_path,'r')\n    ax = plt.subplot(3,3,i + 1)\n    ax.imshow(im)\n    if i == 8:\n        break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nfor i,path in enumerate(os.listdir('../input/aptos2019-blindness-detection/train_images')):\n    img_path = os.path.join('../input/aptos2019-blindness-detection/train_images',path)\n    im = Image.open(img_path,'r')\n    ax = plt.subplot(3,3,i + 1)\n    ax.imshow(im)\n    if i == 8:\n        break","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Okay, it looks like there is a great variety in shape and color in both of train/test dataset.\nTherefore, we would like to investigate the effect of data augmentation. Especially, considering we have different sizes/aspect ratios, we have to crop the images no matter what.\nOne of the topics I would look into is the center crop vs random crop.\n\n  \n"},{"metadata":{},"cell_type":"markdown","source":"## Class balance\nAlso, let's see the class balance within the training set.\nIf there is a huge class imbalance, the likelihood is they are optimized to predict specific class(es), and we definetely would want to avoid that."},{"metadata":{"trusted":true},"cell_type":"code","source":"training_class = pd.read_csv('../input/aptos2019-blindness-detection/train.csv')\nsns.countplot(training_class['diagnosis'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Not that terrible. but probably should consider correcting the balance still.\nThe strategy to correct the balance here is to simply apply data augmentation more on images of less frequent classes. "},{"metadata":{"trusted":true},"cell_type":"code","source":"def data_transforms(mode = 'random',img_size = 256):\n    general_aug = Compose([\n        OneOf([\n            Transpose(),\n            HorizontalFlip(),\n            RandomRotate90()\n            ]),\n        ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.2, rotate_limit=15, p=.2),\n        OneOf([\n            OpticalDistortion(p=0.2),\n            GridDistortion(distort_limit=0.2, p=.1),\n            ElasticTransform(),\n            ], p=1.)\n        ], p=1)\n    image_specific = Compose([\n        OneOf([\n            IAASharpen(),\n            IAAEmboss(),\n            RandomContrast(),\n            RandomBrightness(),\n            ], p=0.3)\n        ])\n    all_transf_pre = [\n            transforms.RandomCrop(round(1.2 * img_size))\n            ]\n\n    all_trans_after = [\n            transforms.CenterCrop(img_size)\n            ]\n    center_crop = [\n            transforms.CenterCrop(img_size)\n    ]\n    normalize = [\n            transforms.ToTensor()\n            ]\n\n    def get_augment(aug):\n        def augment(image):\n            return Image.fromarray(aug(image=np.array(image))['image'])\n        return [augment]\n\n    def normalize_to_full_image(img):\n        return img\n        #img = np.array(img).astype(np.float32)\n        #img -= img.min()\n        #img /= img.max()\n        #img *= 255\n        #return img.astype(np.uint8)\n\n    pre_crop = transforms.Compose(all_transf_pre) \n    train_img_transform = transforms.Compose(get_augment(general_aug) + get_augment(image_specific) + [normalize_to_full_image])\n    norm_transform = transforms.Compose(all_trans_after + normalize)\n    val_transform = transforms.Compose(all_trans_after) if mode == 'random' else transforms.Compose(center_crop)\n\n    return pre_crop, train_img_transform, norm_transform, val_transform","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"For the augmentation, I adopted a variety of techniques, which can be categorized  as follows.\n1. Shape transformation\nThis includes affine transformation, such as rotation, shifting and scaling, flipping and nonlinear transformation.    \n2. Color transformation\nThis includes the change in brightness and contrast. \n\nIn this kernel, I first resized the image to set the aspect ratio of each examples equal and then crops twice before and after applying any data augmentation to keep the black region resulting from data augmentation as small as possible.\nBelow are some examples of augmented samples"},{"metadata":{"trusted":true},"cell_type":"code","source":"pre_crop, train_img_transform, _, center_crop = data_transforms()\nfig = plt.figure()\nfor i,path in enumerate(os.listdir('../input/aptos2019-blindness-detection/train_images')):\n    img_path = os.path.join('../input/aptos2019-blindness-detection/train_images',path)\n    im = Image.open(img_path,'r')\n    im = pre_crop(im.resize((320, 320), resample=Image.BILINEAR))\n    ax = fig.add_subplot(3,2,2 * i + 1)\n    ax.imshow(center_crop(im))\n    ax.set_title('original')\n    ax = fig.add_subplot(3,2,2 * i + 2)\n    ax.set_title('augmented')\n    im = train_img_transform(im)\n    ax.imshow(center_crop(im))\n    \n    if i == 2:\n        break\nfig.suptitle('original vs augmented')\nfig.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def this_collate_fn(batch):\n    elem = batch[0]\n    return {key:torch.cat([d[key] for d in batch],dim = 0) for key in elem} ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv('../input/aptos2019-blindness-detection/train.csv')\ntr, val = train_test_split(train_df, stratify=train_df.diagnosis, test_size=0.05)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class RetinopathyDatasetTrain(Dataset):\n    def __init__(self, data ,img_size = 224):\n        #self.data = pd.read_csv(csv_file)\n        self.data = data.reset_index()\n        most_freq_class_num = len(self.data.query('diagnosis == 0'))\n        self.aug_times = {str(diagnosis):np.round(most_freq_class_num / len(self.data.query('diagnosis == ' + str(diagnosis)))) for diagnosis in self.data['diagnosis'].unique()}\n        \n        #self.images = [Image.open(os.path.join('../input/aptos2019-blindness-detection/train_images',path),'r') for i,path in enumerate(os.listdir('../input/aptos2019-blindness-detection/train_images'))] \n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        self.pre_crop, self.train_img_transform, self.norm_transform, _ = data_transforms()\n        img_name = os.path.join('../input/aptos2019-blindness-detection/train_images', self.data.loc[idx, 'id_code'] + '.png')\n        image = Image.open(img_name)\n        image = self.pre_crop(image.resize((320, 320), resample=Image.BILINEAR))\n        key = str(self.data.loc[idx,'diagnosis'])\n        aug_time = int(self.aug_times[key])\n        img_list = [self.norm_transform(image)] + [self.norm_transform(self.train_img_transform(image)) for i in range(aug_time)]\n        labels = [torch.tensor(self.data.loc[idx,'diagnosis'])] * len(img_list)\n        return {'image': torch.stack(img_list),'label':torch.stack(labels,dim = 0)}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class SEModule(nn.Module):\n\n    def __init__(self, channels, reduction):\n        super(SEModule, self).__init__()\n        self.avg_pool = nn.AdaptiveAvgPool2d(1)\n        self.fc1 = nn.Conv2d(channels, channels // reduction, kernel_size=1,\n                             padding=0)\n        self.relu = nn.ReLU(inplace=True)\n        self.fc2 = nn.Conv2d(channels // reduction, channels, kernel_size=1,\n                             padding=0)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        module_input = x\n        x = self.avg_pool(x)\n        x = self.fc1(x)\n        x = self.relu(x)\n        x = self.fc2(x)\n        x = self.sigmoid(x)\n        return module_input * x\n\n\nclass Bottleneck(nn.Module):\n    \"\"\"\n    Base class for bottlenecks that implements `forward()` method.\n    \"\"\"\n    def forward(self, x):\n        residual = x\n\n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = self.relu(out)\n\n        out = self.conv2(out)\n        out = self.bn2(out)\n        out = self.relu(out)\n\n        out = self.conv3(out)\n        out = self.bn3(out)\n\n        if self.downsample is not None:\n            residual = self.downsample(x)\n\n        out = self.se_module(out) + residual\n        out = self.relu(out)\n\n        return out\n\n\nclass SEBottleneck(Bottleneck):\n    \"\"\"\n    Bottleneck for SENet154.\n    \"\"\"\n    expansion = 4\n\n    def __init__(self, inplanes, planes, groups, reduction, stride=1,\n                 downsample=None):\n        super(SEBottleneck, self).__init__()\n        self.conv1 = nn.Conv2d(inplanes, planes * 2, kernel_size=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(planes * 2)\n        self.conv2 = nn.Conv2d(planes * 2, planes * 4, kernel_size=3,\n                               stride=stride, padding=1, groups=groups,\n                               bias=False)\n        self.bn2 = nn.BatchNorm2d(planes * 4)\n        self.conv3 = nn.Conv2d(planes * 4, planes * 4, kernel_size=1,\n                               bias=False)\n        self.bn3 = nn.BatchNorm2d(planes * 4)\n        self.relu = nn.ReLU(inplace=True)\n        self.se_module = SEModule(planes * 4, reduction=reduction)\n        self.downsample = downsample\n        self.stride = stride","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class SEResNetBottleneck(Bottleneck):\n    \"\"\"\n    ResNet bottleneck with a Squeeze-and-Excitation module. It follows Caffe\n    implementation and uses `stride=stride` in `conv1` and not in `conv2`\n    (the latter is used in the torchvision implementation of ResNet).\n    \"\"\"\n    expansion = 4\n\n    def __init__(self, inplanes, planes, groups, reduction, stride=1,\n                 downsample=None):\n        super(SEResNetBottleneck, self).__init__()\n        self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False,\n                               stride=stride)\n        self.bn1 = nn.BatchNorm2d(planes)\n        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, padding=1,\n                               groups=groups, bias=False)\n        self.bn2 = nn.BatchNorm2d(planes)\n        self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)\n        self.bn3 = nn.BatchNorm2d(planes * 4)\n        self.relu = nn.ReLU(inplace=True)\n        self.se_module = SEModule(planes * 4, reduction=reduction)\n        self.downsample = downsample\n        self.stride = stride\n\n\nclass SEResNeXtBottleneck(Bottleneck):\n    \"\"\"\n    ResNeXt bottleneck type C with a Squeeze-and-Excitation module.\n    \"\"\"\n    expansion = 4\n\n    def __init__(self, inplanes, planes, groups, reduction, stride=1,\n                 downsample=None, base_width=4):\n        super(SEResNeXtBottleneck, self).__init__()\n        width = math.floor(planes * (base_width / 64)) * groups\n        self.conv1 = nn.Conv2d(inplanes, width, kernel_size=1, bias=False,\n                               stride=1)\n        self.bn1 = nn.BatchNorm2d(width)\n        self.conv2 = nn.Conv2d(width, width, kernel_size=3, stride=stride,\n                               padding=1, groups=groups, bias=False)\n        self.bn2 = nn.BatchNorm2d(width)\n        self.conv3 = nn.Conv2d(width, planes * 4, kernel_size=1, bias=False)\n        self.bn3 = nn.BatchNorm2d(planes * 4)\n        self.relu = nn.ReLU(inplace=True)\n        self.se_module = SEModule(planes * 4, reduction=reduction)\n        self.downsample = downsample\n        self.stride = stride\n\n\nclass SENet(nn.Module):\n\n    def __init__(self, block, layers, groups, reduction, dropout_p=0.2,\n                 inplanes=128, input_3x3=True, downsample_kernel_size=3,\n                 downsample_padding=1, num_classes=1000):\n        \"\"\"\n        Parameters\n        ----------\n        block (nn.Module): Bottleneck class.\n            - For SENet154: SEBottleneck\n            - For SE-ResNet models: SEResNetBottleneck\n            - For SE-ResNeXt models:  SEResNeXtBottleneck\n        layers (list of ints): Number of residual blocks for 4 layers of the\n            network (layer1...layer4).\n        groups (int): Number of groups for the 3x3 convolution in each\n            bottleneck block.\n            - For SENet154: 64\n            - For SE-ResNet models: 1\n            - For SE-ResNeXt models:  32\n        reduction (int): Reduction ratio for Squeeze-and-Excitation modules.\n            - For all models: 16\n        dropout_p (float or None): Drop probability for the Dropout layer.\n            If `None` the Dropout layer is not used.\n            - For SENet154: 0.2\n            - For SE-ResNet models: None\n            - For SE-ResNeXt models: None\n        inplanes (int):  Number of input channels for layer1.\n            - For SENet154: 128\n            - For SE-ResNet models: 64\n            - For SE-ResNeXt models: 64\n        input_3x3 (bool): If `True`, use three 3x3 convolutions instead of\n            a single 7x7 convolution in layer0.\n            - For SENet154: True\n            - For SE-ResNet models: False\n            - For SE-ResNeXt models: False\n        downsample_kernel_size (int): Kernel size for downsampling convolutions\n            in layer2, layer3 and layer4.\n            - For SENet154: 3\n            - For SE-ResNet models: 1\n            - For SE-ResNeXt models: 1\n        downsample_padding (int): Padding for downsampling convolutions in\n            layer2, layer3 and layer4.\n            - For SENet154: 1\n            - For SE-ResNet models: 0\n            - For SE-ResNeXt models: 0\n        num_classes (int): Number of outputs in `last_linear` layer.\n            - For all models: 1000\n        \"\"\"\n        super(SENet, self).__init__()\n        self.inplanes = inplanes\n        if input_3x3:\n            layer0_modules = [\n                ('conv1', nn.Conv2d(3, 64, 3, stride=2, padding=1,\n                                    bias=False)),\n                ('bn1', nn.BatchNorm2d(64)),\n                ('relu1', nn.ReLU(inplace=True)),\n                ('conv2', nn.Conv2d(64, 64, 3, stride=1, padding=1,\n                                    bias=False)),\n                ('bn2', nn.BatchNorm2d(64)),\n                ('relu2', nn.ReLU(inplace=True)),\n                ('conv3', nn.Conv2d(64, inplanes, 3, stride=1, padding=1,\n                                    bias=False)),\n                ('bn3', nn.BatchNorm2d(inplanes)),\n                ('relu3', nn.ReLU(inplace=True)),\n            ]\n        else:\n            layer0_modules = [\n                ('conv1', nn.Conv2d(3, inplanes, kernel_size=7, stride=2,\n                                    padding=3, bias=False)),\n                ('bn1', nn.BatchNorm2d(inplanes)),\n                ('relu1', nn.ReLU(inplace=True)),\n            ]\n        # To preserve compatibility with Caffe weights `ceil_mode=True`\n        # is used instead of `padding=1`.\n        layer0_modules.append(('pool', nn.MaxPool2d(3, stride=2,\n                                                    ceil_mode=True)))\n        self.layer0 = nn.Sequential(OrderedDict(layer0_modules))\n        self.layer1 = self._make_layer(\n            block,\n            planes=64,\n            blocks=layers[0],\n            groups=groups,\n            reduction=reduction,\n            downsample_kernel_size=1,\n            downsample_padding=0\n        )\n        self.layer2 = self._make_layer(\n            block,\n            planes=128,\n            blocks=layers[1],\n            stride=2,\n            groups=groups,\n            reduction=reduction,\n            downsample_kernel_size=downsample_kernel_size,\n            downsample_padding=downsample_padding\n        )\n        self.layer3 = self._make_layer(\n            block,\n            planes=256,\n            blocks=layers[2],\n            stride=2,\n            groups=groups,\n            reduction=reduction,\n            downsample_kernel_size=downsample_kernel_size,\n            downsample_padding=downsample_padding\n        )\n        self.layer4 = self._make_layer(\n            block,\n            planes=512,\n            blocks=layers[3],\n            stride=2,\n            groups=groups,\n            reduction=reduction,\n            downsample_kernel_size=downsample_kernel_size,\n            downsample_padding=downsample_padding\n        )\n        self.avg_pool = nn.AvgPool2d(7, stride=1)\n        self.dropout = nn.Dropout(dropout_p) if dropout_p is not None else None\n        self.last_linear = nn.Linear(512 * block.expansion, num_classes)\n\n    def _make_layer(self, block, planes, blocks, groups, reduction, stride=1,\n                    downsample_kernel_size=1, downsample_padding=0):\n        downsample = None\n        if stride != 1 or self.inplanes != planes * block.expansion:\n            downsample = nn.Sequential(\n                nn.Conv2d(self.inplanes, planes * block.expansion,\n                          kernel_size=downsample_kernel_size, stride=stride,\n                          padding=downsample_padding, bias=False),\n                nn.BatchNorm2d(planes * block.expansion),\n            )\n\n        layers = []\n        layers.append(block(self.inplanes, planes, groups, reduction, stride,\n                            downsample))\n        self.inplanes = planes * block.expansion\n        for i in range(1, blocks):\n            layers.append(block(self.inplanes, planes, groups, reduction))\n\n        return nn.Sequential(*layers)\n\n    def features(self, x):\n        x = self.layer0(x)\n        x = self.layer1(x)\n        x = self.layer2(x)\n        x = self.layer3(x)\n        x = self.layer4(x)\n        return x\n\n    def logits(self, x):\n        x = self.avg_pool(x)\n        if self.dropout is not None:\n            x = self.dropout(x)\n        x = x.view(x.size(0), -1)\n        x = self.last_linear(x)\n        return x\n\n    def forward(self, x):\n        x = self.features(x)\n        x = self.logits(x)\n        return x\n\n\n\n\ndef se_resnext50_32x4d(num_classes=1000, pretrained= True):\n    model = SENet(SEResNeXtBottleneck, [3, 4, 6, 3], groups=32, reduction=16,\n                  dropout_p=None, inplanes=64, input_3x3=False,\n                  downsample_kernel_size=1, downsample_padding=0,\n                  num_classes=num_classes)\n    if pretrained:\n        pretrained_state = torch.load(\"../input/seresnext50/seresnext50.pth\")\n        #model_dict = model.state_dict()\n        #pretrained_state = {k: v for k, v in pretrained_state.items() if k in model_dict}\n        model.load_state_dict(pretrained_state)\n    return model\n\ndef se_resnext101_32x4d(num_classes=1000, pretrained='imagenet'):\n    model = SENet(SEResNeXtBottleneck, [3, 4, 23, 3], groups=32, reduction=16,\n                  dropout_p=None, inplanes=64, input_3x3=False,\n                  downsample_kernel_size=1, downsample_padding=0,\n                  num_classes=num_classes)\n    if pretrained:\n        pretrained_state = torch.load(\"../input/pritrained-se-resnet-101/se_resnext101_32x4d-3b2fe3d8.pth\")\n        #model_dict = model.state_dict()\n        #pretrained_state = {k: v for k, v in pretrained_state.items() if k in model_dict}\n        model.load_state_dict(pretrained_state)\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#model = torchvision.models.resnext50_32x4d(pretrained=False)\nmodel = se_resnext101_32x4d()\nmodel.last_linear = nn.Linear(8192,5)\nmodel = model.to(device)\noptimizer = torch.optim.Adam(model.parameters(),lr = 1e-3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_ds = RetinopathyDatasetTrain(tr)\nval_ds = RetinopathyDatasetTest(val,mode = 'val')\ntrain_loader = torch.utils.data.DataLoader(train_ds, batch_size=8,collate_fn=this_collate_fn, shuffle = True, num_workers=4)\nval_loader = torch.utils.data.DataLoader(val_ds, batch_size=32, shuffle = False, num_workers=4)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#test_preds = np.zeros((len(test_dataset), 1))\ncriterion = nn.CrossEntropyLoss()\nfor epoch in range(epochs):\n    train_loss = []\n    val_loss = []\n    model.train()\n    for i, x_batch in enumerate(train_loader):\n        \n        model.zero_grad()\n        img = x_batch[\"image\"]\n        img = img.to(device).float()\n        label = x_batch['label'].to(device).long()\n        output = model(img)\n        loss = criterion(output,label)\n        train_loss.append(loss)\n        loss.backward()\n        optimizer.step()   \n    model.eval()\n    with torch.no_grad():\n        for j,x_batch in enumerate(val_loader):\n            img = x_batch[\"image\"]\n            img = img.to(device).float()\n            label = x_batch['label'].to(device).long()\n            output = model(img)\n            loss = criterion(output,label)\n            val_loss.append(loss)\n    train_mean_loss = torch.mean(torch.stack(train_loss)).data.cpu().numpy()\n    val_mean_loss = torch.mean(torch.stack(val_loss)).data.cpu().numpy()\n        \n    print(f'Epoch {epoch}, train loss: {train_mean_loss:.4f}, valid loss: {val_mean_loss:.4f}.')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nfor param in model.parameters():\n    param.requires_grad = False\n\nmodel.eval()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ntest_df = pd.read_csv('../input/aptos2019-blindness-detection/test.csv')\ntest_dataset = RetinopathyDatasetTest(test_df,mode = 'test')\ntest_data_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False, num_workers=4)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ntest_preds = np.zeros((len(test_dataset), 1))\n\nfor i, x_batch in enumerate(test_data_loader):\n    x_batch = x_batch[\"image\"]\n    _,pred = torch.max(model(x_batch.to(device)),1)\n    test_preds[i * 32:(i + 1) * 32] = pred.cpu().squeeze().numpy().ravel().reshape(-1, 1)\n\"\"\"    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nsample = pd.read_csv(\"../input/aptos2019-blindness-detection/sample_submission.csv\")\nsample.diagnosis = test_preds.astype(int)\nsample.to_csv(\"submission.csv\", index=False)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* To do; improve some data augmentations to avoid obviously wrong ones\n"}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}