{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Configuration"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import pandas as pd\nbatch_size = 1\nimage_size = 640\ntta = True\nsubmit = True\nenet_type_512 = ['resnet200d'] * 5\nenet_type_640 = ['resnet200d'] * 5\nenet_type_800 = ['resnet200d'] * 5\n# model_path = ['../input/5foldsize640/resnet200d_fold0_roc0.9573779406064133_640.pth',\n#               '../input/5foldsize640/resnet200d_fold1_roc0.958675971156162_640.pth',\n#               '../input/5foldsize640/resnet200d_fold2_roc0.9601304280323029_640.pth',\n#               '../input/5foldsize640/resnet200d_fold3_roc0.9604036613971542_640.pth',\n#               '../input/5foldsize640/resnet200d_fold4_roc0.9583824135304986_640.pth']\nmodel_path_512 = ['../input/ranzcr-submit/resnet200d_fold0_roc0.9599744377006669_512_LB_96.4.pth',\n                  '../input/ranzcr-submit/checkpoint14_fold1.pt',\n                  '../input/ranzcr-submit/checkpoint14_fold2.pt',\n                  '../input/ranzcr-submit/checkpoint12_fold3.pt',\n                  '../input/ranzcr-submit/checkpoint11_fold4.pt'\n                 ]\nmodel_path_640 = ['../input/fold01640softlabels/resnet200d_fold0_roc0.961664002708935_640_LB_96.5.pth',\n                  '../input/fold01640softlabels/resnet200d_fold1_roc0.9603313504962234_640_LB_96.2.pth',\n                  '../input/fold01640softlabels/resnet200d_fold2_roc0.9643361401940415_640_LB_96.3.pth',\n                  '../input/fold01640softlabels/resnet200d_fold3_roc0.9632528323431991_640_LB_96.3.pth',\n                  '../input/fold01640softlabels/resnet200d_fold4_roc0.9625872475042488_640_LB_96.5.pth']\n# model_copy = ['../input/resnet200quan/resnet200d_q.pth']\nmodel_path_800 = ['../input/fold800softlabels/resnet200d_fold0_roc0.9620559690764665_800.pth',\n                  '../input/fold800softlabels/resnet200d_fold1_roc0.9636014053091645_800_LB_96.6.pth',\n                  '../input/fold800softlabels/resnet200d_fold2_roc0.9651701266058569_800_LB_96.6.pth',\n                  '../input/fold800softlabels/resnet200d_fold3_roc0.9649471502568004_800_LB_96.7.pth',\n                  '../input/fold800softlabels/resnet200d_fold4_roc0.9640653819309057_800.pth']\n# you can save GPU quota using fast sub attached in the last markdown file\nfast_sub = False\nfast_sub_path = '../input/xxxxxx/your_submission.csv'","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Imports"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import os\nimport sys\nsys.path.append('../input/pytorch-images-seresnet')\nsys.path.append('../input/pytorch-image-models/pytorch-image-models-master')\nsys.path.append('../input/timm-pytorch-image-models/pytorch-image-models-master')\nimport numpy as np\nDEBUG = False\nimport time\nimport cv2\nimport PIL.Image\nfrom PIL import Image\nfrom sklearn.metrics import accuracy_score\nfrom tqdm.notebook import tqdm\nimport torch\nfrom torch.utils.data import DataLoader, Dataset\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torchvision\nimport torchvision.transforms as transforms\nimport torch.optim as optim\nfrom torch.optim.lr_scheduler import CosineAnnealingLR\nimport albumentations\nfrom tqdm.notebook import tqdm\nimport matplotlib.pyplot as plt\n%matplotlib inline\nimport seaborn as sns\nfrom pylab import rcParams\nimport timm\nimport random\nfrom albumentations import *\nfrom albumentations.pytorch import ToTensorV2\ndevice = torch.device('cuda') if not DEBUG else torch.device('cpu')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def set_seed(seed = 42):\n    '''Sets the seed of the entire notebook so results are the same every time we run.\n    This is for REPRODUCIBILITY.'''\n    np.random.seed(seed)\n    random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    # When running on the CuDNN backend, two further options must be set\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = True\n    # Set a fixed value for the hash seed\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    \nset_seed(2021)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"class PAM_Module(nn.Module):\n    \"\"\" Position attention module\"\"\"\n    #Ref from SAGAN\n    def __init__(self, in_dim):\n        super(PAM_Module, self).__init__()\n        self.chanel_in = in_dim\n\n        self.query_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim//8, kernel_size=1)\n        self.key_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim//8, kernel_size=1)\n        self.value_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim, kernel_size=1)\n        self.gamma = nn.Parameter(torch.zeros(1))\n\n    def forward(self, x):\n        \"\"\"\n            inputs :\n                x : input feature maps( B X C X H X W)\n            returns :\n                out : attention value + input feature\n                attention: B X (HxW) X (HxW)\n        \"\"\"\n        m_batchsize, C, height, width = x.size()\n        proj_query = self.query_conv(x).view(m_batchsize, -1, width*height).permute(0, 2, 1)\n        proj_key = self.key_conv(x).view(m_batchsize, -1, width*height)\n        energy = torch.bmm(proj_query, proj_key)\n        attention = torch.softmax(energy, dim=-1)\n        proj_value = self.value_conv(x).view(m_batchsize, -1, width*height)\n\n        out = torch.bmm(proj_value, attention.permute(0, 2, 1))\n        out = out.view(m_batchsize, C, height, width)\n\n        out = self.gamma*out + x\n        return out\n\n\nclass CAM_Module(nn.Module):\n    \"\"\" Channel attention module\"\"\"\n    def __init__(self, in_dim):\n        super(CAM_Module, self).__init__()\n        self.chanel_in = in_dim\n        self.gamma = nn.Parameter(torch.zeros(1))\n\n    def forward(self,x):\n        \"\"\"\n            inputs :\n                x : input feature maps( B X C X H X W)\n            returns :\n                out : attention value + input feature\n                attention: B X C X C\n        \"\"\"\n        m_batchsize, C, height, width = x.size()\n        proj_query = x.view(m_batchsize, C, -1)\n        proj_key = x.view(m_batchsize, C, -1).permute(0, 2, 1)\n        energy = torch.bmm(proj_query, proj_key)\n        energy_new = torch.max(energy, -1, keepdim=True)[0].expand_as(energy)-energy\n        attention = torch.softmax(energy_new, dim=-1)\n        proj_value = x.view(m_batchsize, C, -1)\n\n        out = torch.bmm(attention, proj_value)\n        out = out.view(m_batchsize, C, height, width)\n\n        out = self.gamma*out + x\n        return out\n\n\nclass CBAM(nn.Module):\n    def __init__(self, in_channels):\n        # def __init__(self):\n        super(CBAM, self).__init__()\n        inter_channels = in_channels // 4\n        self.conv1_c = nn.Sequential(nn.Conv2d(in_channels, inter_channels, 3, padding=1, bias=False),\n                                     nn.BatchNorm2d(inter_channels),\n                                     nn.ReLU())\n        \n        self.conv1_s = nn.Sequential(nn.Conv2d(in_channels, inter_channels, 3, padding=1, bias=False),\n                                     nn.BatchNorm2d(inter_channels),\n                                     nn.ReLU())\n\n        self.channel_gate = CAM_Module(inter_channels)\n        self.spatial_gate = PAM_Module(inter_channels)\n\n        self.conv2_c = nn.Sequential(nn.Conv2d(inter_channels, in_channels, 3, padding=1, bias=False),\n                                     nn.BatchNorm2d(in_channels),\n                                     nn.ReLU())\n        self.conv2_a = nn.Sequential(nn.Conv2d(inter_channels, in_channels, 3, padding=1, bias=False),\n                                     nn.BatchNorm2d(in_channels),\n                                     nn.ReLU())\n\n    def forward(self, x):\n        feat1 = self.conv1_c(x)\n        chnl_att = self.channel_gate(feat1)\n        chnl_att = self.conv2_c(chnl_att)\n\n        feat2 = self.conv1_s(x)\n        spat_att = self.spatial_gate(feat2)\n        spat_att = self.conv2_a(spat_att)\n\n        x_out = chnl_att + spat_att\n\n        return x_out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class RANZCRResNet200D_CBAM(nn.Module):\n    def __init__(self, model_name='resnet200d', out_dim=11, pretrained=False):\n        super().__init__()\n        self.model = timm.create_model(model_name, pretrained=False)\n        n_features = self.model.fc.in_features\n        self.model.global_pool = nn.Identity()\n        self.model.fc = nn.Identity()\n        # self.model.layer4 = BotStackLayer\n        self.model.layer5000 = CBAM(2048)\n        self.pooling = nn.AdaptiveAvgPool2d(1)\n        self.fc = nn.Linear(n_features, out_dim)\n        \n    def forward(self, x):\n        bs = x.size(0)\n        features = self.model(x)\n        pooled_features = self.pooling(features).view(bs, -1)\n        output = self.fc(pooled_features)\n        return output","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class ResNet200D(nn.Module):\n    def __init__(self, model_name='resnet200d'):\n        super().__init__()\n        self.model = timm.create_model(model_name, pretrained=False)\n        n_features = self.model.fc.in_features\n        self.model.global_pool = nn.Identity()\n        self.model.fc = nn.Identity()\n        self.pooling = nn.AdaptiveAvgPool2d(1)\n        self.fc = nn.Linear(n_features, 11)\n\n    def forward(self, x):\n        bs = x.size(0)\n        features = self.model(x)\n        pooled_features = self.pooling(features).view(bs, -1)\n        output = self.fc(pooled_features)\n        return output\n\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Transforms"},{"metadata":{},"cell_type":"markdown","source":"## Dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy\ndef trim(im):\n    bbox = im.getbbox()\n    if bbox:\n        return im.crop(bbox)\n    else: \n        return im\n\n# Rotate the image around its center\ndef rotateImage(cvImage, angle: float):\n    newImage = cvImage.copy()\n    (h, w) = newImage.shape[:2]\n    center = (w // 2, h // 2)\n    M = cv2.getRotationMatrix2D(center, angle, 1.0)\n    newImage = cv2.warpAffine(newImage, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)\n    return newImage\n\n# Deskew image\ndef deskew(cvImage, angle):\n    return rotateImage(cvImage, -1.0 * angle)\n\ndef preprocess_image(img_path):\n    image = Image.open(img_path).convert('RGB')\n    pil_image = trim(image)\n    original_image = numpy.array(pil_image)\n    # cv2.imwrite(\"remove border.jpg\", original_image)\n    gray = numpy.array(pil_image.convert('L'))\n    thresh = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY)[1]\n    cnts, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)\n    cnts = sorted(cnts, key=cv2.contourArea, reverse=True)\n    minAreaRect = cv2.minAreaRect(cv2.convexHull(cnts[0], False))\n\n    angle = minAreaRect[-1]\n    if angle < -45:\n        angle = 90 + angle\n\n    return deskew(original_image, -1.0 * angle)\n\nclass RANZCRDataset(Dataset):\n    def __init__(self, df, mode, transform=None):\n        \n        self.df = df.reset_index(drop=True)\n        self.mode = mode\n        self.transform = transform\n        self.labels = df[target_cols].values\n        \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, index):\n        row = self.df.loc[index]\n        img = preprocess_image(row.file_path)\n        \n        if self.transform is not None:\n            img_1 = self.transform(image=img)['image']\n            img_2 = self.transform(image=img)['image']\n            img_2 = img_2.flip(-1)\n        \n        return img_1, img_2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test = pd.read_csv('../input/ranzcr-clip-catheter-line-classification/sample_submission.csv')\ntest['file_path'] = test.StudyInstanceUID.apply(lambda x: os.path.join('../input/ranzcr-clip-catheter-line-classification/test', f'{x}.jpg'))\ntarget_cols = test.iloc[:, 1:12].columns.tolist()\nif len(test) == 3582:\n    test = test[0:8]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"transforms_test_800 = albumentations.Compose([\n            Resize(800, 800),\n#             HorizontalFlip(p=0.5),\n#             RandomBrightnessContrast(brightness_limit=(-0.1,0.1), contrast_limit=(-0.1, 0.1), p=0.5),\n#             ShiftScaleRotate(shift_limit = 0.2 ,scale_limit = 0.2, rotate_limit = 20, p=0.5),\n            Normalize(\n                 mean=[0.485, 0.456, 0.406],\n                 std=[0.229, 0.224, 0.225],\n             ),\n            ToTensorV2()\n        ], p=1.)\n\ntest_dataset_800 = RANZCRDataset(test, 'test', transform=transforms_test_800)\ntest_loader_800 = torch.utils.data.DataLoader(test_dataset_800, batch_size=12, shuffle=False,  num_workers=4)\ntest_preds_800 = []\n\nmodels = []\nfor i in range(len(enet_type_800)):\n    model = RANZCRResNet200D_CBAM(enet_type_800[i], out_dim=len(target_cols))\n    model = model.to(device)\n    model.load_state_dict(torch.load(model_path_800[i], map_location='cuda:0'))\n    model.eval()\n    models.append(model)\n\nPREDS = []\nfor i in range(len(models)):\n    PREDS.append([])\nwith torch.no_grad():\n    for (images_1, images_2) in test_loader_800:\n        x1 = images_1.to(device)\n        x2 = images_2.to(device)\n        tmp = []\n        for i in range(len(models)):\n            avg_prob = np.zeros((images_1.shape[0], 11))\n            logits_1 = models[i](x1)\n            logits_2 = models[i](x2)\n            avg_prob += logits_1.sigmoid().detach().cpu().numpy()\n            avg_prob += logits_2.sigmoid().detach().cpu().numpy()\n            for j in range(images_1.shape[0]):\n                PREDS[i].append(avg_prob[j]/2)\n\nfor i in range(len(models)):\n    PREDS[i] = np.array(PREDS[i])  \nfor i in range(len(enet_type_800)):\n    model = models[i]\n    del model\n    torch.cuda.empty_cache()\n        \ntest_preds_800 = PREDS","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"transforms_test_640 = albumentations.Compose([\n            Resize(640, 640),\n#             HorizontalFlip(p=0.5),\n#             RandomBrightnessContrast(brightness_limit=(-0.1,0.1), contrast_limit=(-0.1, 0.1), p=0.5),\n#             ShiftScaleRotate(shift_limit = 0.2 ,scale_limit = 0.2, rotate_limit = 20, p=0.5),\n            Normalize(\n                 mean=[0.485, 0.456, 0.406],\n                 std=[0.229, 0.224, 0.225],\n             ),\n            ToTensorV2()\n        ], p=1.)\n\ntest_dataset_640 = RANZCRDataset(test, 'test', transform=transforms_test_640)\ntest_loader_640 = torch.utils.data.DataLoader(test_dataset_640, batch_size=16, shuffle=False,  num_workers=4)\n\ntest_preds_640 = []\n\nmodels = []\nfor i in range(len(enet_type_640)):\n    model = RANZCRResNet200D_CBAM(enet_type_640[i], out_dim=len(target_cols))\n    model = model.to(device)\n    model.load_state_dict(torch.load(model_path_640[i], map_location='cuda:0'))\n    model.eval()\n    models.append(model)\n\nPREDS = []\nmodel_640_all = ResNet200D()\nmodel_640_all = model_640_all.to(device)\nmodel_640_all.load_state_dict(torch.load('../input/ranzcr-resnet200d-320/checkpoint4.pt', map_location='cuda:0'))\nmodel_640_all.eval()\nPREDS_640_ALL = []\n\nwith torch.no_grad():\n    for (images_1, images_2) in test_loader_640:\n        avg_prob = np.zeros((images_1.shape[0], 11))\n        avg_prob_640_all = np.zeros((images_1.shape[0], 11))\n\n        x1 = images_1.to(device)\n        x2 = images_2.to(device)\n        for i in range(len(models)):\n            logits_1 = models[i](x1)\n            logits_2 = models[i](x2)\n            avg_prob += logits_1.sigmoid().detach().cpu().numpy()\n            avg_prob += logits_2.sigmoid().detach().cpu().numpy()\n        logits_1_640_all = model_640_all(x1)\n        logits_2_640_all = model_640_all(x2)\n        avg_prob_640_all += logits_1_640_all.sigmoid().detach().cpu().numpy()\n        avg_prob_640_all += logits_2_640_all.sigmoid().detach().cpu().numpy()\n        \n        for j in range(images_1.shape[0]):\n            PREDS.append(avg_prob[j]/(2*len(models)))\n            PREDS_640_ALL.append(avg_prob_640_all[j]/2)\n\nPREDS = np.array(PREDS) \nPREDS_640_ALL = np.array(PREDS_640_ALL)         \n\nfor i in range(len(enet_type_640)):\n    model = models[i]\n    del model\n    torch.cuda.empty_cache()\n\ndel model_640_all\ntorch.cuda.empty_cache()        \ntest_preds_640 = PREDS\ntest_preds_640_all = PREDS_640_ALL","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"transforms_test_512 = albumentations.Compose([\n            Resize(512, 512),\n#             HorizontalFlip(p=0.5),\n#             RandomBrightnessContrast(brightness_limit=(-0.1,0.1), contrast_limit=(-0.1, 0.1), p=0.5),\n#             ShiftScaleRotate(shift_limit = 0.2 ,scale_limit = 0.2, rotate_limit = 20, p=0.5),\n            Normalize(\n                 mean=[0.485, 0.456, 0.406],\n                 std=[0.229, 0.224, 0.225],\n             ),\n            ToTensorV2()\n        ], p=1.)\n\ntest_dataset_512 = RANZCRDataset(test, 'test', transform=transforms_test_512)\ntest_loader_512 = torch.utils.data.DataLoader(test_dataset_512, batch_size=32, shuffle=False,  num_workers=4)\n\ntest_preds_512 = []\nmodels = []\nfor i in range(len(enet_type_512)):\n    model = RANZCRResNet200D_CBAM(enet_type_512[i], out_dim=len(target_cols))\n    model = model.to(device)\n    model.load_state_dict(torch.load(model_path_512[i], map_location='cuda:0'))\n    model.eval()\n    models.append(model)\n\nPREDS = []\nwith torch.no_grad():\n    for (images_1, images_2) in test_loader_512:\n        avg_prob = np.zeros((images_1.shape[0], 11))\n        x1 = images_1.to(device)\n        x2 = images_2.to(device)\n        tmp = []\n        for i in range(len(models)):\n            logits_1 = models[i](x1)\n            logits_2 = models[i](x2)\n            avg_prob += logits_1.sigmoid().detach().cpu().numpy()\n            avg_prob += logits_2.sigmoid().detach().cpu().numpy()\n        for j in range(images_1.shape[0]):\n            PREDS.append(avg_prob[j]/(2*len(models)))\n\nPREDS = np.array(PREDS)  \nfor i in range(len(enet_type_512)):\n    model = models[i]\n    del model\n    torch.cuda.empty_cache()\n        \ntest_preds_512 = PREDS","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_preds = (0.5*test_preds_512 + test_preds_640 + 0.5*test_preds_800[0] + test_preds_800[1]+ test_preds_800[2]+ test_preds_800[3]+ 0.5*test_preds_800[4] + test_preds_640_all)/6.5\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission = pd.read_csv('../input/ranzcr-clip-catheter-line-classification/sample_submission.csv')\nif len(submission) == 3582:\n    submission = submission[0:8]\nsubmission[target_cols] = test_preds\nsubmission.to_csv('submission.csv', index=False)\nsubmission.head()","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}